blob: d33ee91381a7281706685637f96b655b80c7e823 [file] [log] [blame]
/*
* Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE 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 "qdf_util.h"
#include "cds_concurrency.h"
#include "wma.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}
} },
{144,
{{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}
} },
{144,
{{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}
} },
{144,
{{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 QDF_STATUS sap_get_channel_list(ptSapContext sapContext,
uint8_t **channelList,
uint8_t *numberOfChannels);
#endif
/*==========================================================================
FUNCTION sap_get_5ghz_channel_list
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 QDF_STATUS sap_get_5ghz_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_REMAIN_CHAN_READY);
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_INTERRUPTED);
CASE_RETURN_STRING(eSAP_DFS_CAC_END);
CASE_RETURN_STRING(eSAP_DFS_PRE_CAC_END);
CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT);
CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC);
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);
CASE_RETURN_STRING(eSAP_ECSA_CHANGE_CHAN_IND);
CASE_RETURN_STRING(eSAP_UPDATE_SCAN_RESULT);
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
/*
* sap_find_target_channel_in_channel_matrix() - finds the leakage matrix
* @sapContext: Pointer to vos global context structure
* @ch_width: target channel width
* @NOL_channel: the NOL channel whose leakage matrix is required
* @pTarget_chnl_mtrx: pointer to target channel matrix returned.
*
* This function gives the leakage matrix for given NOL channel and ch_width
*
* Return: TRUE or FALSE
*/
static bool
sap_find_target_channel_in_channel_matrix(ptSapContext sapContext,
enum phy_ch_width ch_width,
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 (ch_width) {
case CH_WIDTH_20MHZ:
/* HT20 */
pchan_matrix = ht20_chan;
nchan_matrix = QDF_ARRAY_SIZE(ht20_chan);
break;
case CH_WIDTH_40MHZ:
/* HT40 */
pchan_matrix = ht40_chan;
nchan_matrix = QDF_ARRAY_SIZE(ht40_chan);
break;
case CH_WIDTH_80MHZ:
/* HT80 */
pchan_matrix = ht80_chan;
nchan_matrix = QDF_ARRAY_SIZE(ht80_chan);
break;
default:
/* handle exception and fall back to HT20 table */
pchan_matrix = ht20_chan;
nchan_matrix = QDF_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_leaking_ch() - to mark channel leaking in to nol
* @sap_ctx: pointer to SAP context
* @ch_width: channel width
* @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: QDF_STATUS
*/
static QDF_STATUS
sap_mark_leaking_ch(ptSapContext sap_ctx,
enum phy_ch_width ch_width,
tSapDfsNolInfo *nol,
uint8_t temp_ch_lst_sz,
uint8_t *temp_ch_lst)
{
tSapTxLeakInfo *target_chan_matrix = NULL;
uint32_t num_channel = (CHAN_ENUM_144 - CHAN_ENUM_36) + 1;
uint32_t i = 0;
uint32_t j = 0;
uint32_t k = 0;
uint8_t dfs_nol_channel;
tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->pvosGCtx);
tpAniSirGlobal mac;
if (NULL == hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"%s: Invalid hal pointer", __func__);
return QDF_STATUS_E_FAULT;
}
mac = PMAC_STRUCT(hal);
/* 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;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
FL("sapdfs: processing NOL channel: %d"),
dfs_nol_channel);
if (false == sap_find_target_channel_in_channel_matrix(
sap_ctx, ch_width, dfs_nol_channel,
&target_chan_matrix)) {
/*
* should never happen, we should always find a table
* here, if we don't, need a fix here!
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Couldn't find target channel matrix!"));
QDF_ASSERT(0);
return QDF_STATUS_E_FAILURE;
}
/*
* following is based on assumption that both temp_ch_lst
* and target channel matrix are in increasing order of
* ch_id
*/
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 <=
mac->sap.SapDfsInfo.tx_leakage_threshold) {
/*
* candidate channel will have
* bad leakage in NOL channel,
* remove from temp list
*/
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_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;
}
j++;
k++;
}
} /* end of loop that selects each NOL */
return QDF_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;
}
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Channel=%d is not in the bitmap"), channel);
}
/**
* sap_populate_available_channels() - To populate available channel
* @bitmap: bitmap to populate
* @ch_width: channel width
* @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,
enum phy_ch_width ch_width,
uint8_t *avail_chnl)
{
uint8_t i = 0;
uint8_t chnl_count = 0;
uint8_t start_channel = 0;
switch (ch_width) {
/* VHT80 */
case CH_WIDTH_160MHZ:
case CH_WIDTH_80P80MHZ:
case CH_WIDTH_80MHZ:
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;
/* HT40 */
case CH_WIDTH_40MHZ:
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;
}
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:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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))) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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))) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 */
/**
* sap_is_valid_acs_channel() - checks if given channel is in acs channel range
* @sap_ctx: sap context.
* @channel: channel to be checked in acs range
*
* Return: true, if channel is valid, false otherwise.
*/
static bool sap_is_valid_acs_channel(ptSapContext sap_ctx, uint8_t channel)
{
int i = 0;
/* Check whether acs is enabled */
if (!sap_ctx->acs_cfg->acs_mode)
return true;
if ((channel < sap_ctx->acs_cfg->start_ch) ||
(channel > sap_ctx->acs_cfg->end_ch)) {
return false;
}
if (!sap_ctx->acs_cfg->ch_list) {
/* List not present, return */
return true;
} else {
for (i = 0; i < sap_ctx->acs_cfg->ch_list_count; i++)
if (channel == sap_ctx->acs_cfg->ch_list[i])
return true;
}
return false;
}
/**
* sap_apply_rules() - validates channels in sap_ctx channel list
* @sap_ctx: sap context pointer
*
* This function takes the channel list in sap_ctx and marks invalid channel
* based on following rules:
* -> invalid due to different reg domain dfs channel list
* -> already present in NOL
* -> outside ACS range or not
* -> not usable due to another SAP operating MCC mode in same channel
* -> preferred location is indoors or outdoors
*
* Return: number of valid channels after applying all the rules
*/
static uint8_t sap_apply_rules(ptSapContext sap_ctx)
{
uint8_t num_valid_ch, i = 0, ch_id;
tAll5GChannelList *sap_all_ch = &sap_ctx->SapAllChnlList;
bool is_ch_nol = false;
bool is_valid_acs_chan = false;
tpAniSirGlobal mac_ctx;
tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx);
uint8_t preferred_location;
enum dfs_region dfs_region;
if (NULL == hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("hal pointer NULL"));
return 0;
}
mac_ctx = PMAC_STRUCT(hal);
if (NULL == mac_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("mac_ctx pointer NULL"));
return 0;
}
preferred_location =
mac_ctx->sap.SapDfsInfo.sap_operating_chan_preferred_location;
cds_get_dfs_region(&dfs_region);
/* loop to check ACS range or NOL channels */
num_valid_ch = sap_all_ch->numChannel;
for (i = 0; i < sap_all_ch->numChannel; i++) {
ch_id = sap_all_ch->channelList[i].channel;
/*
* IN MKK DFS REGION 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_MKK_REGION == dfs_region) {
/*
* Check for JAPAN W53 Channel operation capability
*/
if (true == sap_dfs_is_w53_invalid(hal, ch_id)) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_LOW,
FL("index:%d, Channel=%d Invalid,Japan W53 Disabled"),
i, ch_id);
sap_all_ch->channelList[i].valid = false;
num_valid_ch--;
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(hal,
ch_id)) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_LOW,
FL("CHAN=%d is invalid,preferred Channel Location %d Only"),
ch_id, preferred_location);
sap_all_ch->channelList[i].valid = false;
num_valid_ch--;
continue;
}
}
if (cds_get_channel_state(ch_id) == CHANNEL_STATE_DFS) {
is_ch_nol = sap_dfs_is_channel_in_nol_list(sap_ctx,
ch_id, PHY_SINGLE_CHANNEL_CENTERED);
if (true == is_ch_nol) {
/*
* Mark this channel invalid since it is still
* in DFS Non-Occupancy-Period which is 30 mins.
*/
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_LOW,
FL("index: %d, Channel = %d Present in NOL LIST"),
i, ch_id);
sap_all_ch->channelList[i].valid = false;
num_valid_ch--;
continue;
}
}
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
/* avoid ch on which another MDM AP in MCC mode is detected */
if (mac_ctx->sap.sap_channel_avoidance
&& sap_ctx->sap_detected_avoid_ch_ie.present) {
if (sap_check_in_avoid_ch_list(sap_ctx, ch_id)) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_LOW,
FL("index: %d, Channel = %d, avoided due to presence of another AP+AP MCC device in same channel."),
i, ch_id);
sap_all_ch->channelList[i].valid = false;
}
}
#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
/* check if the channel is within ACS channel range */
is_valid_acs_chan = sap_is_valid_acs_channel(sap_ctx, ch_id);
if (is_valid_acs_chan == false) {
/*
* mark this channel invalid since it is out of ACS
* channel range
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("index=%d, Channel=%d out of ACS chan range %d-%d"),
i, ch_id, sap_ctx->acs_cfg->start_ch,
sap_ctx->acs_cfg->end_ch);
sap_all_ch->channelList[i].valid = false;
num_valid_ch--;
continue;
}
} /* end of check for NOL or ACS channels */
return num_valid_ch;
}
/**
* select_rand_from_lst() - selects random channel from given list
* @mac_ctx: mac context pointer
* @ch_lst: channel list
* @num_ch: number of channels
*
* Return: new target channel randomly selected
*/
static uint8_t select_rand_from_lst(tpAniSirGlobal mac_ctx, uint8_t *ch_lst,
uint8_t num_ch)
{
uint32_t rand_byte = 0;
uint8_t i, target_channel, non_dfs_num_ch = 0, dfs_num_ch = 0;
uint8_t dfs_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0};
uint8_t non_dfs_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0};
if (num_ch) {
for (i = 0; i < num_ch; i++) {
if (CDS_IS_DFS_CH(ch_lst[i]))
dfs_ch[dfs_num_ch++] = ch_lst[i];
else
non_dfs_ch[non_dfs_num_ch++] = ch_lst[i];
}
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("No target channel found"));
return 0;
}
cds_rand_get_bytes(0, (uint8_t *)&rand_byte, 1);
/* Give preference to non-DFS channel */
if (!mac_ctx->f_prefer_non_dfs_on_radar) {
i = (rand_byte + qdf_mc_timer_get_system_ticks()) % num_ch;
target_channel = ch_lst[i];
} else if (non_dfs_num_ch) {
i = (rand_byte + qdf_mc_timer_get_system_ticks()) %
non_dfs_num_ch;
target_channel = non_dfs_ch[i];
} else {
i = (rand_byte + qdf_mc_timer_get_system_ticks()) % dfs_num_ch;
target_channel = dfs_ch[i];
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("sapdfs: New Channel width = %d"),
mac_ctx->sap.SapDfsInfo.new_chanWidth);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("sapdfs: target_channel = %d"), target_channel);
return target_channel;
}
/**
* sap_find_ch_wh_fallback() - find given channel width from given list of
* channels
* @mac_ctx: mac context pointer
* @ch_wd: channel width to find
* @ch_lst: list of channels
* @num_ch: number of channels
*
* This function tries to find given channel width and returns new target ch.
* If not found updates ch_wd to next lower channel width.
*
* Return: new target channel if successful, 0 otherwise
*/
static uint8_t sap_find_ch_wh_fallback(tpAniSirGlobal mac_ctx,
enum phy_ch_width *ch_wd,
uint8_t *ch_lst,
uint8_t num_ch)
{
bool flag = false;
uint32_t rand_byte = 0;
chan_bonding_bitmap ch_map = { { {0} } };
uint8_t count = 0, i, index = 0, final_cnt = 0, target_channel = 0;
uint8_t primary_seg_start_ch = 0, sec_seg_ch = 0, new_160_start_ch = 0;
uint8_t final_lst[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0};
/* initialize ch_map for all 80 MHz bands: we have 6 80MHz bands */
ch_map.chanBondingSet[0].startChannel = 36;
ch_map.chanBondingSet[1].startChannel = 52;
ch_map.chanBondingSet[2].startChannel = 100;
ch_map.chanBondingSet[3].startChannel = 116;
ch_map.chanBondingSet[4].startChannel = 132;
ch_map.chanBondingSet[5].startChannel = 149;
/* now loop through leakage free list */
for (i = 0; i < num_ch; i++) {
/* add tmp ch to bitmap */
if (ch_lst[i] == 0)
continue;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
FL("sapdfs: Channel=%d added to bitmap"),
ch_lst[i]);
sap_set_bitmap(&ch_map, ch_lst[i]);
}
/* populate available channel list from bitmap */
final_cnt = sap_populate_available_channels(&ch_map, *ch_wd, final_lst);
/* If no valid ch bonding found, fallback */
if (final_cnt == 0) {
if ((*ch_wd == CH_WIDTH_160MHZ) ||
(*ch_wd == CH_WIDTH_80P80MHZ) ||
(*ch_wd == CH_WIDTH_80MHZ)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
FL("sapdfs:Changing chanWidth from [%d] to 40Mhz"),
*ch_wd);
*ch_wd = CH_WIDTH_40MHZ;
} else if (*ch_wd == CH_WIDTH_40MHZ) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
FL("sapdfs:No 40MHz cb found, falling to 20MHz"));
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
FL("sapdfs:Changing chanWidth from [%d] to [%d]"),
*ch_wd, CH_WIDTH_20MHZ);
*ch_wd = CH_WIDTH_20MHZ;
}
return 0;
}
/* ch count should be > 8 to switch new channel in 160Mhz band */
if (((*ch_wd == CH_WIDTH_160MHZ) || (*ch_wd == CH_WIDTH_80P80MHZ)) &&
(final_cnt < SIR_DFS_MAX_20M_SUB_CH)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
FL("sapdfs:Changing chanWidth from [%d] to [%d]"),
*ch_wd, CH_WIDTH_80MHZ);
*ch_wd = CH_WIDTH_80MHZ;
return 0;
}
if (*ch_wd == CH_WIDTH_160MHZ) {
/*
* NA supports only 2 blocks for 160Mhz bandwidth i.e 36-64 &
* 100-128 and all the channels in these blocks are continuous
* and seperated by 4Mhz.
*/
for (i = 1; ((i < final_cnt)); i++) {
if ((final_lst[i] - final_lst[i-1]) == 4)
count++;
else
count = 0;
if (count == SIR_DFS_MAX_20M_SUB_CH - 1) {
flag = true;
new_160_start_ch = final_lst[i-7];
break;
}
}
} else if (*ch_wd == CH_WIDTH_80P80MHZ) {
flag = true;
}
if ((flag == false) && (*ch_wd > CH_WIDTH_80MHZ)) {
*ch_wd = CH_WIDTH_80MHZ;
return 0;
}
if (*ch_wd == CH_WIDTH_160MHZ) {
cds_rand_get_bytes(0, (uint8_t *)&rand_byte, 1);
rand_byte = (rand_byte + qdf_mc_timer_get_system_ticks())
% SIR_DFS_MAX_20M_SUB_CH;
target_channel = new_160_start_ch + (rand_byte * 4);
} else if (*ch_wd == CH_WIDTH_80P80MHZ) {
cds_rand_get_bytes(0, (uint8_t *)&rand_byte, 1);
index = (rand_byte + qdf_mc_timer_get_system_ticks()) %
final_cnt;
target_channel = final_lst[index];
index -= (index % 4);
primary_seg_start_ch = final_lst[index];
/* reset channels associate with primary 80Mhz */
for (i = 0; i < 4; i++)
final_lst[i + index] = 0;
/* select and calculate center freq for secondary segement */
for (i = 0; i < final_cnt / 4; i++) {
if (final_lst[i * 4] &&
(abs(primary_seg_start_ch - final_lst[i * 4]) >
(SIR_DFS_MAX_20M_SUB_CH * 2))) {
sec_seg_ch = final_lst[i * 4] +
SIR_80MHZ_START_CENTER_CH_DIFF;
break;
}
}
if (!sec_seg_ch && (final_cnt == SIR_DFS_MAX_20M_SUB_CH))
*ch_wd = CH_WIDTH_160MHZ;
else if (!sec_seg_ch)
*ch_wd = CH_WIDTH_80MHZ;
mac_ctx->sap.SapDfsInfo.new_ch_params.center_freq_seg1
= sec_seg_ch;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("sapdfs: New Center Freq Seg1 = %d"), sec_seg_ch);
} else {
target_channel = select_rand_from_lst(mac_ctx, final_lst,
final_cnt);
}
return target_channel;
}
/**
* sap_random_channel_sel() - This function randomly pick up an available
* channel
* @sap_ctx: sap context.
*
* This function first eliminates invalid channel, then selects random channel
* using following algorithm:
* PASS: 1 - invalidate ch in sap_ctx->all_ch_lst as per rules
* PASS: 2 - now mark channels that will leak into NOL
* PASS: 3 - from leakage_adjusted_lst, either select random channel (for 20MHz)
* or find given channel width possible. if not found fallback to
* lower channel width and try again. once given channel width found
* use random channel from give possibilities.
* Return: channel number picked
*/
static uint8_t sap_random_channel_sel(ptSapContext sap_ctx)
{
uint8_t j = 0, i = 0, final_cnt = 0, target_channel = 0;
/* count and ch list after applying all rules */
uint8_t rule_adjusted_cnt, *rule_adjusted_lst;
/* ch list after invalidating channels leaking into NOL */
uint8_t *leakage_adjusted_lst;
/* final list of channel from which random channel will be selected */
uint8_t final_lst[QDF_MAX_NUM_CHAN] = {0};
tAll5GChannelList *all_ch = &sap_ctx->SapAllChnlList;
tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx);
tpAniSirGlobal mac_ctx;
/* channel width for current iteration */
enum phy_ch_width ch_wd;
#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION
tSapDfsNolInfo *nol;
#endif
if (NULL == hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("invalid hal"));
return 0;
}
mac_ctx = PMAC_STRUCT(hal);
if (NULL == mac_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("invalid mac_ctx"));
return 0;
}
/*
* 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 (mac_ctx->sap.SapDfsInfo.orig_chanWidth == 0) {
ch_wd = sap_ctx->ch_width_orig;
mac_ctx->sap.SapDfsInfo.orig_chanWidth = ch_wd;
} else {
ch_wd = mac_ctx->sap.SapDfsInfo.orig_chanWidth;
}
if (sap_get_5ghz_channel_list(sap_ctx)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("Getting 5Ghz channel list failed"));
return 0;
}
/* PASS: 1 - invalidate ch in sap_ctx->all_ch_lst as per rules */
rule_adjusted_cnt = sap_apply_rules(sap_ctx);
if (0 == rule_adjusted_cnt) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("No channels left after applying rules."));
return 0;
}
/* this is list we get after applying all rules */
rule_adjusted_lst = qdf_mem_malloc(rule_adjusted_cnt);
/* list adjusted after leakage has been marked */
leakage_adjusted_lst = qdf_mem_malloc(rule_adjusted_cnt);
if (rule_adjusted_lst == NULL || leakage_adjusted_lst == NULL) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("sapdfs: memory alloc failed"));
qdf_mem_free(rule_adjusted_lst);
qdf_mem_free(leakage_adjusted_lst);
return 0;
}
/* copy valid ch from sap_ctx->all_ch_lst into rule_adjusted_lst */
for (i = 0, j = 0; i < all_ch->numChannel; i++) {
if (!all_ch->channelList[i].valid)
continue;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("sapdfs: Adding Channel = %d to temp List"),
all_ch->channelList[i].channel);
rule_adjusted_lst[j++] = all_ch->channelList[i].channel;
}
/*
* do - while loop for fallback mechanism. at each channel width this
* will try to find channel bonding, if not fall back to lower ch width
*/
do {
/* save rules adjusted lst */
qdf_mem_copy(leakage_adjusted_lst, rule_adjusted_lst,
rule_adjusted_cnt);
#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION
nol = mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("sapdfs: Processing tmp ch list against NOL."));
/* PASS: 2 - now mark channels that will leak into NOL */
if (sap_mark_leaking_ch(sap_ctx, ch_wd, nol, rule_adjusted_cnt,
leakage_adjusted_lst) != QDF_STATUS_SUCCESS) {
qdf_mem_free(rule_adjusted_lst);
qdf_mem_free(leakage_adjusted_lst);
return 0;
}
#endif
if (ch_wd == CH_WIDTH_20MHZ) {
/*
* PASS: 3 - from leakage_adjusted_lst, prepare valid
* ch list and use random number from that
*/
for (i = 0; i < rule_adjusted_cnt; i++) {
if (leakage_adjusted_lst[i] == 0)
continue;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_DEBUG,
FL("sapdfs: Channel=%d added to available list"),
leakage_adjusted_lst[i]);
final_lst[final_cnt] = leakage_adjusted_lst[i];
final_cnt++;
}
target_channel = select_rand_from_lst(mac_ctx,
final_lst, final_cnt);
break;
}
/*
* PASS: 3 - following function will check from valid channels
* left if given ch_wd can be supported. if not reduce ch_wd
* (fallback), then continue with reduced ch_wd
*/
target_channel = sap_find_ch_wh_fallback(mac_ctx, &ch_wd,
leakage_adjusted_lst,
rule_adjusted_cnt);
/*
* if target channel is 0, no channel bonding was found
* ch_wd would have been updated for fallback
*/
if (0 == target_channel)
continue;
else
break;
} while (true);
if (target_channel) {
mac_ctx->sap.SapDfsInfo.new_chanWidth = ch_wd;
mac_ctx->sap.SapDfsInfo.new_ch_params.ch_width = ch_wd;
}
qdf_mem_free(rule_adjusted_lst);
qdf_mem_free(leakage_adjusted_lst);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("sapdfs: New Channel width = %d"),
mac_ctx->sap.SapDfsInfo.new_chanWidth);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("sapdfs: target_channel = %d"),
target_channel);
return target_channel;
}
/**
* 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
*/
static 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;
uint64_t time_elapsed_since_last_radar;
uint64_t time_when_radar_found;
hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx);
if (NULL == channels)
return;
if (NULL == hHal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("invalid hHal"));
return;
}
pMac = PMAC_STRUCT(hHal);
if (NULL == pMac) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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;
time_when_radar_found =
psapDfsChannelNolList[j].radar_found_timestamp;
time_elapsed_since_last_radar = time -
time_when_radar_found;
/*
* 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) &&
(time_elapsed_since_last_radar <
SAP_DFS_NON_OCCUPANCY_PERIOD)) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_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;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_HIGH,
FL("Channel=%d Added to NOL LIST"),
channels[i]);
}
}
}
/*
* sap_get_bonding_channels() - get bonding channels from primary channel.
* @sapContext: Handle to SAP context.
* channel: Channel to get bonded channels.
* channels: Bonded channel list
* size: Max bonded channels
* chanBondState: The channel bonding mode of the passed channel.
*
* Return: Number of sub channels
*/
static 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;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
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;
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;
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.
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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.
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("Chan=%d in NOL, Channel UNAVAILBLE"),
nol->dfs_channel_number);
return false;
}
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid Radar Status Flag"));
}
return true;
}
/**
* sap_ch_params_to_bonding_channels() - get bonding channels from channel param
* @ch_params: channel params ( bw, pri and sec channel info)
* @channels: bonded channel list
*
* Return: Number of sub channels
*/
static uint8_t sap_ch_params_to_bonding_channels(
struct ch_params_s *ch_params,
uint8_t *channels)
{
uint8_t center_chan = ch_params->center_freq_seg0;
uint8_t nchannels = 0;
switch (ch_params->ch_width) {
case CH_WIDTH_160MHZ:
nchannels = 8;
center_chan = ch_params->center_freq_seg1;
channels[0] = center_chan - 14;
channels[1] = center_chan - 10;
channels[2] = center_chan - 6;
channels[3] = center_chan - 2;
channels[4] = center_chan + 2;
channels[5] = center_chan + 6;
channels[6] = center_chan + 10;
channels[7] = center_chan + 14;
break;
case CH_WIDTH_80P80MHZ:
nchannels = 8;
channels[0] = center_chan - 6;
channels[1] = center_chan - 2;
channels[2] = center_chan + 2;
channels[3] = center_chan + 6;
center_chan = ch_params->center_freq_seg1;
channels[4] = center_chan - 6;
channels[5] = center_chan - 2;
channels[6] = center_chan + 2;
channels[7] = center_chan + 6;
break;
case CH_WIDTH_80MHZ:
nchannels = 4;
channels[0] = center_chan - 6;
channels[1] = center_chan - 2;
channels[2] = center_chan + 2;
channels[3] = center_chan + 6;
break;
case CH_WIDTH_40MHZ:
nchannels = 2;
channels[0] = center_chan - 2;
channels[1] = center_chan + 2;
break;
default:
nchannels = 1;
channels[0] = center_chan;
break;
}
return nchannels;
}
/**
* 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 = 0, 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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
FL("invalid dfs channel count %d"),
dfs_info->numCurrentRegDomainDfsChannels);
return false;
}
/* get the bonded channels */
if (channel_number == sap_context->channel && chan_bondState >=
PHY_CHANNEL_BONDING_STATE_MAX)
num_channels = sap_ch_params_to_bonding_channels(
&sap_context->ch_params, channels);
else
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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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;
}
uint8_t sap_select_default_oper_chan(struct sap_acs_cfg *acs_cfg)
{
uint8_t channel;
if (NULL == acs_cfg) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"ACS config invalid!");
QDF_BUG(0);
return 0;
}
if (acs_cfg->hw_mode == eCSR_DOT11_MODE_11a) {
channel = SAP_DEFAULT_5GHZ_CHANNEL;
} else if ((acs_cfg->hw_mode == eCSR_DOT11_MODE_11n) ||
(acs_cfg->hw_mode == eCSR_DOT11_MODE_11n_ONLY) ||
(acs_cfg->hw_mode == eCSR_DOT11_MODE_11ac) ||
(acs_cfg->hw_mode == eCSR_DOT11_MODE_11ac_ONLY)) {
if (CDS_IS_CHANNEL_5GHZ(acs_cfg->start_ch))
channel = SAP_DEFAULT_5GHZ_CHANNEL;
else
channel = SAP_DEFAULT_24GHZ_CHANNEL;
} else {
channel = SAP_DEFAULT_24GHZ_CHANNEL;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("channel selected to start bss %d"), channel);
return channel;
}
/**
* 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.
* @check_for_connection_update: true, check and wait for connection update
* false, do not perform connection update
*
* Initiates sme scan for ACS to pick a channel.
*
* Return: The QDF_STATUS code associated with performing the operation.
*/
QDF_STATUS sap_goto_channel_sel(ptSapContext sap_context,
ptWLAN_SAPEvent sap_event,
bool sap_do_acs_pre_start_bss,
bool check_for_connection_update)
{
/* Initiate a SCAN request */
QDF_STATUS qdf_ret_status;
/* To be initialised if scan is required */
tCsrScanRequest scan_request;
uint32_t scan_req_id;
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpAniSirGlobal mac_ctx;
#ifdef SOFTAP_CHANNEL_RANGE
uint8_t *channel_list = NULL;
uint8_t num_of_channels = 0;
#endif
tHalHandle h_hal;
uint8_t con_ch;
bool sta_sap_scc_on_dfs_chan;
h_hal = cds_get_context(QDF_MODULE_ID_SME);
if (NULL == h_hal) {
/* we have a serious problem */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL,
FL("invalid h_hal"));
return QDF_STATUS_E_FAULT;
}
mac_ctx = PMAC_STRUCT(h_hal);
if (NULL == mac_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid MAC context"));
return QDF_STATUS_E_FAILURE;
}
if (cds_concurrent_beaconing_sessions_running()) {
con_ch =
sme_get_concurrent_operation_channel(h_hal);
#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE
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)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
FL("MCC DFS not supported in AP_AP Mode"));
return QDF_STATUS_E_ABORTED;
}
#endif
#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
if (sap_context->cc_switch_mode !=
QDF_MCC_TO_SCC_SWITCH_DISABLE &&
sap_context->channel) {
/*
* For ACS request ,the sapContext->channel is 0,
* we skip below overlap checking. When the ACS
* finish and SAPBSS start, the sapContext->channel
* will not be 0. Then the overlap checking will be
* reactivated.If we use sapContext->channel = 0
* to perform the overlap checking, an invalid overlap
* channel con_ch could becreated. That may cause
* SAP start failed.
*/
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) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"%s: Override ch %d to %d due to CC Intf",
__func__, sap_context->channel, con_ch);
sap_context->channel = con_ch;
cds_set_channel_params(sap_context->channel, 0,
&sap_context->ch_params);
}
}
#endif
}
if (cds_get_concurrency_mode() == (QDF_STA_MASK | QDF_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)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN,
FL("DFS not supported in STA_AP Mode"));
return QDF_STATUS_E_ABORTED;
}
#endif
#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
if (sap_context->cc_switch_mode !=
QDF_MCC_TO_SCC_SWITCH_DISABLE &&
sap_context->channel) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("check for overlap: chan:%d mode:%d"),
sap_context->channel,
sap_context->csr_roamProfile.phyMode);
con_ch = sme_check_concurrent_channel_overlap(h_hal,
sap_context->channel,
sap_context->csr_roamProfile.phyMode,
sap_context->cc_switch_mode);
if (QDF_IS_STATUS_ERROR(
cds_valid_sap_conc_channel_check(&con_ch,
sap_context->channel))) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_WARN,
FL("SAP can't start (no MCC)"));
return QDF_STATUS_E_ABORTED;
}
sta_sap_scc_on_dfs_chan =
cds_is_sta_sap_scc_allowed_on_dfs_channel();
if (con_ch && cds_is_safe_channel(con_ch) &&
(!CDS_IS_DFS_CH(con_ch) ||
(CDS_IS_DFS_CH(con_ch) &&
sta_sap_scc_on_dfs_chan))) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"%s: Override ch %d to %d due to CC Intf",
__func__, sap_context->channel,
con_ch);
sap_context->channel = con_ch;
cds_set_channel_params(sap_context->channel, 0,
&sap_context->ch_params);
}
}
#endif
}
if (sap_context->channel == AUTO_CHANNEL_SELECT) {
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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
qdf_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;
if (ACS_FW_REPORT_PARAM_CONFIGURED)
scan_request.BSSType = eCSR_BSS_TYPE_INFRA_AP;
#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;
if (sap_context->channelList) {
qdf_mem_free(sap_context->channelList);
sap_context->channelList = NULL;
sap_context->num_of_channel = 0;
}
sap_context->channelList = channel_list;
sap_context->num_of_channel = num_of_channels;
#endif
wma_get_scan_id(&scan_req_id);
scan_request.scan_id = scan_req_id;
/* Set requestType to Full scan */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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
*/
qdf_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
*/
qdf_ret_status = sme_scan_request(h_hal,
sap_context->sessionId,
&scan_request,
&wlansap_scan_callback,
sap_context);
}
if (QDF_STATUS_SUCCESS != qdf_ret_status) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("sme_scan_request fail %d!!!"),
qdf_ret_status);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("SAP Configuring default channel, Ch=%d"),
sap_context->channel);
sap_context->channel = sap_select_default_oper_chan(
sap_context->acs_cfg);
#ifdef SOFTAP_CHANNEL_RANGE
if (sap_context->channelList != NULL) {
sap_context->channel =
sap_context->channelList[0];
qdf_mem_free(sap_context->
channelList);
sap_context->channelList = NULL;
sap_context->num_of_channel = 0;
}
#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 QDF_STATUS_E_FAILURE;
} else {
/* Fill in the event structure */
sap_event_init(sap_event);
/* Handle event */
qdf_status = sap_fsm(sap_context, sap_event);
}
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("## %s SKIPPED ACS SCAN"), __func__);
if (true == sap_do_acs_pre_start_bss)
wlansap_pre_start_bss_acs_scan_callback(h_hal,
sap_context, sap_context->sessionId, 0,
eCSR_SCAN_SUCCESS);
else
wlansap_scan_callback(h_hal, sap_context,
sap_context->sessionId, 0, eCSR_SCAN_SUCCESS);
}
#endif
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("for configured channel, Ch= %d"),
sap_context->channel);
if (check_for_connection_update) {
/* This wait happens in the hostapd context. The event
* is set in the MC thread context.
*/
qdf_status = cds_update_and_wait_for_connection_update(
sap_context->sessionId,
sap_context->channel,
SIR_UPDATE_REASON_START_AP);
if (QDF_IS_STATUS_ERROR(qdf_status))
return qdf_status;
}
if (sap_do_acs_pre_start_bss == true) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 QDF_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 */
qdf_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
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("before exiting sap_goto_channel_sel channel=%d"),
sap_context->channel);
return QDF_STATUS_SUCCESS;
}
/**
* sap_open_session() - Opens a SAP session
* @hHal: Hal handle
* @sapContext: Sap Context value
* @session_id: Pointer to the session id
*
* Function for opening SME and SAP sessions when system is in SoftAP role
*
* Return: QDF_STATUS
*/
QDF_STATUS sap_open_session(tHalHandle hHal, ptSapContext sapContext,
uint32_t *session_id)
{
uint32_t type, subType;
QDF_STATUS qdf_ret_status;
QDF_STATUS status = QDF_STATUS_E_FAILURE;
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
if (sapContext->csr_roamProfile.csrPersona == QDF_P2P_GO_MODE)
status = cds_get_vdev_types(QDF_P2P_GO_MODE, &type, &subType);
else
status = cds_get_vdev_types(QDF_SAP_MODE, &type, &subType);
if (QDF_STATUS_SUCCESS != status) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL,
"failed to get vdev type");
return QDF_STATUS_E_FAILURE;
}
qdf_event_reset(&sapContext->sap_session_opened_evt);
/* Open SME Session for Softap */
qdf_ret_status = sme_open_session(hHal,
&wlansap_roam_callback,
sapContext,
sapContext->self_mac_addr,
&sapContext->sessionId, type, subType);
if (QDF_STATUS_SUCCESS != qdf_ret_status) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"Error: In %s calling sme_roam_connect status = %d",
__func__, qdf_ret_status);
return QDF_STATUS_E_FAILURE;
}
status = qdf_wait_for_event_completion(
&sapContext->sap_session_opened_evt,
SME_CMD_TIMEOUT_VALUE);
if (!QDF_IS_STATUS_SUCCESS(status)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"wait for sap open session event timed out");
return QDF_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;
*session_id = sapContext->sessionId;
sapContext->isSapSessionOpen = true;
sapContext->is_pre_cac_on = false;
sapContext->pre_cac_complete = false;
sapContext->chan_before_pre_cac = 0;
sapContext->enable_etsi_srd_chan_support =
pMac->sap.enable_etsi_srd_chan_support;
if (sapContext->csr_roamProfile.csrPersona == QDF_SAP_MODE)
sme_cli_set_command(*session_id,
WMI_VDEV_PARAM_ENABLE_DISABLE_RTT_RESPONDER_ROLE,
(bool)(pMac->fine_time_meas_cap & WMI_FW_AP_RTT_RESPR),
VDEV_CMD);
return QDF_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 QDF_STATUS code associated with performing the operation
QDF_STATUS_SUCCESS: Success
SIDE EFFECTS
============================================================================*/
static QDF_STATUS sap_goto_starting(ptSapContext sapContext,
ptWLAN_SAPEvent sapEvent,
eCsrRoamBssType bssType)
{
/* tHalHandle */
tHalHandle hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx);
QDF_STATUS qdf_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;
/* Need a key size define */
qdf_mem_copy(sapContext->key_material, key_material,
sizeof(key_material));
if (NULL == hHal) {
/* we have a serious problem */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL,
"In %s, invalid hHal", __func__);
return QDF_STATUS_E_FAULT;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, "%s: session: %d",
__func__, sapContext->sessionId);
qdf_ret_status = sme_roam_connect(hHal, sapContext->sessionId,
&sapContext->csr_roamProfile,
&sapContext->csr_roamId);
if (QDF_STATUS_SUCCESS != qdf_ret_status)
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"%s: Failed to issue sme_roam_connect", __func__);
return qdf_ret_status;
} /* 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 QDF_STATUS code associated with performing the operation
QDF_STATUS_SUCCESS: Success
SIDE EFFECTS
============================================================================*/
static QDF_STATUS sap_goto_disconnecting(ptSapContext sapContext)
{
QDF_STATUS qdf_ret_status;
tHalHandle hHal;
hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx);
if (NULL == hHal) {
/* we have a serious problem */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"In %s, invalid hHal", __func__);
return QDF_STATUS_E_FAULT;
}
sap_free_roam_profile(&sapContext->csr_roamProfile);
qdf_ret_status = sme_roam_stop_bss(hHal, sapContext->sessionId);
if (QDF_STATUS_SUCCESS != qdf_ret_status) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"Error: In %s calling sme_roam_stop_bss status = %d",
__func__, qdf_ret_status);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS sap_roam_session_close_callback(void *pContext)
{
ptSapContext sapContext = (ptSapContext) pContext;
QDF_STATUS status;
status = wlansap_context_get(pContext);
if (status != QDF_STATUS_SUCCESS) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"%s: sap context has already been freed", __func__);
return status;
}
status = sap_signal_hdd_event(sapContext, NULL,
eSAP_STOP_BSS_EVENT,
(void *) eSAP_STATUS_SUCCESS);
wlansap_context_put(pContext);
return status;
}
/*==========================================================================
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 QDF_STATUS code associated with performing the operation
QDF_STATUS_SUCCESS: Success
SIDE EFFECTS
============================================================================*/
static QDF_STATUS sap_goto_disconnected(ptSapContext sapContext)
{
QDF_STATUS qdf_status = QDF_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 */
qdf_status = sap_fsm(sapContext, &sapEvent);
return qdf_status;
}
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
/**
* sap_handle_acs_scan_event() - handle acs scan event for SAP
* @sap_context: ptSapContext
* @sap_event: tSap_Event
* @status: status of acs scan
*
* The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event.
*
* Return: void
*/
static void sap_handle_acs_scan_event(ptSapContext sap_context,
tSap_Event *sap_event, eSapStatus status)
{
sap_event->sapHddEventCode = eSAP_ACS_SCAN_SUCCESS_EVENT;
sap_event->sapevt.sap_acs_scan_comp.status = status;
sap_event->sapevt.sap_acs_scan_comp.num_of_channels =
sap_context->num_of_channel;
sap_event->sapevt.sap_acs_scan_comp.channellist =
sap_context->channelList;
}
#else
static void sap_handle_acs_scan_event(ptSapContext sap_context,
tSap_Event *sap_event, eSapStatus status)
{
}
#endif
/**
* 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: QDF_STATUS
*/
QDF_STATUS sap_signal_hdd_event(ptSapContext sap_ctx,
tCsrRoamInfo *csr_roaminfo, eSapHddEvent sap_hddevent,
void *context)
{
QDF_STATUS qdf_status = QDF_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;
/* Format the Start BSS Complete event to return... */
if (NULL == sap_ctx->pfnSapEventCallback) {
return QDF_STATUS_E_FAILURE;
}
if (NULL == hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid hal"));
return QDF_STATUS_E_FAILURE;
}
mac_ctx = PMAC_STRUCT(hal);
if (NULL == mac_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid MAC context"));
return QDF_STATUS_E_FAILURE;
}
if (sap_hddevent != eSAP_UPDATE_SCAN_RESULT)
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
/* TODO - Indicate the assoc request indication to OS */
sap_ap_event.sapHddEventCode = eSAP_STA_ASSOC_IND;
assoc_ind = &sap_ap_event.sapevt.sapAssocIndication;
qdf_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;
assoc_ind->ecsa_capable = csr_roaminfo->ecsa_capable;
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;
bss_complete->staId = sap_ctx->sap_sta_id;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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_PRE_CAC_END:
case eSAP_DFS_RADAR_DETECT:
case eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC:
case eSAP_DFS_NO_AVAILABLE_CHANNEL:
sap_ap_event.sapHddEventCode = sap_hddevent;
sap_ap_event.sapevt.sapStopBssCompleteEvent.status =
(eSapStatus) context;
break;
case eSAP_ACS_SCAN_SUCCESS_EVENT:
sap_handle_acs_scan_event(sap_ctx, &sap_ap_event,
(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:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
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;
qdf_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;
qdf_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;
qdf_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;
qdf_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;
chaninfo->nss = csr_roaminfo->chan_info.nss;
chaninfo->rate_flags = csr_roaminfo->chan_info.rate_flags;
reassoc_complete->wmmEnabled = csr_roaminfo->wmmEnabledSta;
reassoc_complete->status = (eSapStatus) context;
reassoc_complete->timingMeasCap = csr_roaminfo->timingMeasCap;
reassoc_complete->ecsa_capable = csr_roaminfo->ecsa_capable;
reassoc_complete->ampdu = csr_roaminfo->ampdu;
reassoc_complete->sgi_enable = csr_roaminfo->sgi_enable;
reassoc_complete->tx_stbc = csr_roaminfo->tx_stbc;
reassoc_complete->rx_stbc = csr_roaminfo->rx_stbc;
reassoc_complete->ch_width = csr_roaminfo->ch_width;
reassoc_complete->mode = csr_roaminfo->mode;
reassoc_complete->max_supp_idx = csr_roaminfo->max_supp_idx;
reassoc_complete->max_ext_idx = csr_roaminfo->max_ext_idx;
reassoc_complete->max_mcs_idx = csr_roaminfo->max_mcs_idx;
reassoc_complete->rx_mcs_map = csr_roaminfo->rx_mcs_map;
reassoc_complete->tx_mcs_map = csr_roaminfo->tx_mcs_map;
if (csr_roaminfo->ht_caps.present)
reassoc_complete->ht_caps = csr_roaminfo->ht_caps;
if (csr_roaminfo->vht_caps.present)
reassoc_complete->vht_caps = csr_roaminfo->vht_caps;
break;
case eSAP_STA_LOSTLINK_DETECTED:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
sap_ap_event.sapHddEventCode = eSAP_STA_LOSTLINK_DETECTED;
disassoc_comp =
&sap_ap_event.sapevt.sapStationDisassocCompleteEvent;
qdf_copy_macaddr(&disassoc_comp->staMac,
&csr_roaminfo->peerMac);
disassoc_comp->reason_code = csr_roaminfo->reasonCode;
break;
case eSAP_STA_DISASSOC_EVENT:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
sap_ap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT;
disassoc_comp =
&sap_ap_event.sapevt.sapStationDisassocCompleteEvent;
qdf_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:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
sap_ap_event.sapHddEventCode = eSAP_STA_SET_KEY_EVENT;
key_complete =
&sap_ap_event.sapevt.sapStationSetKeyCompleteEvent;
key_complete->status = (eSapStatus) context;
qdf_copy_macaddr(&key_complete->peerMacAddr,
&csr_roaminfo->peerMac);
break;
case eSAP_STA_MIC_FAILURE_EVENT:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
sap_ap_event.sapHddEventCode = eSAP_STA_MIC_FAILURE_EVENT;
mic_failure = &sap_ap_event.sapevt.sapStationMICFailureEvent;
qdf_mem_copy(&mic_failure->srcMacAddr,
csr_roaminfo->u.pMICFailureInfo->srcMacAddr,
sizeof(tSirMacAddr));
qdf_mem_copy(&mic_failure->staMac.bytes,
csr_roaminfo->u.pMICFailureInfo->taMacAddr,
sizeof(tSirMacAddr));
qdf_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;
qdf_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:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
sap_ap_event.sapHddEventCode = eSAP_WPS_PBC_PROBE_REQ_EVENT;
qdf_mem_copy(&sap_ap_event.sapevt.sapPBCProbeReqEvent.
WPSPBCProbeReq, csr_roaminfo->u.pWPSPBCProbeReq,
sizeof(tSirWPSPBCProbeReq));
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_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;
qdf_mem_copy((void *) sap_ap_event.sapevt.sapUnknownSTAJoin.
macaddr.bytes, (void *) context,
QDF_MAC_ADDR_SIZE);
break;
case eSAP_MAX_ASSOC_EXCEEDED:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
sap_ap_event.sapHddEventCode = eSAP_MAX_ASSOC_EXCEEDED;
qdf_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->csr_roamProfile.ch_params.ch_width;
sap_config_acs_result(hal, sap_ctx,
sap_ctx->csr_roamProfile.ch_params.sec_ch_offset);
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->csr_roamProfile.ch_params.ch_width;
acs_selected->vht_seg0_center_ch =
sap_ctx->csr_roamProfile.ch_params.center_freq_seg0;
acs_selected->vht_seg1_center_ch =
sap_ctx->csr_roamProfile.ch_params.center_freq_seg1;
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;
case eSAP_ECSA_CHANGE_CHAN_IND:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"In %s, SAP event callback event = %s",
__func__, "eSAP_ECSA_CHANGE_CHAN_IND");
sap_ap_event.sapHddEventCode = eSAP_ECSA_CHANGE_CHAN_IND;
sap_ap_event.sapevt.sap_chan_cng_ind.new_chan =
csr_roaminfo->target_channel;
break;
case eSAP_UPDATE_SCAN_RESULT:
if (!csr_roaminfo) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid CSR Roam Info"));
return QDF_STATUS_E_INVAL;
}
sap_ap_event.sapHddEventCode = eSAP_UPDATE_SCAN_RESULT;
sap_ap_event.sapevt.bss_desc = csr_roaminfo->pBssDesc;
break;
case eSAP_STOP_BSS_DUE_TO_NO_CHNL:
sap_ap_event.sapHddEventCode = eSAP_STOP_BSS_DUE_TO_NO_CHNL;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
FL("stopping session_id:%d, bssid:%pM, channel:%d"),
sap_ctx->sessionId, sap_ctx->self_mac_addr,
sap_ctx->channel);
break;
default:
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("SAP Unknown callback event = %d"),
sap_hddevent);
break;
}
qdf_status = (*sap_ctx->pfnSapEventCallback)
(&sap_ap_event, sap_ctx->pUsrContext);
return qdf_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
============================================================================*/
static ptSapContext sap_find_valid_concurrent_session(tHalHandle hHal)
{
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
uint8_t intf = 0;
ptSapContext sapContext;
for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) {
if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona)
||
(QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) &&
pMac->sap.sapCtxList[intf].pSapContext != NULL) {
sapContext = pMac->sap.sapCtxList[intf].pSapContext;
if (sapContext->sapsMachine != eSAP_DISCONNECTED)
return sapContext;
}
}
return NULL;
}
/**
* sap_find_cac_wait_session() - Get context of a SAP session in CAC wait state
* @handle: Global MAC handle
*
* Finds and gets the context of a SAP session in CAC wait state.
*
* Return: Valid SAP context on success, else NULL
*/
static ptSapContext sap_find_cac_wait_session(tHalHandle handle)
{
tpAniSirGlobal mac = PMAC_STRUCT(handle);
uint8_t i = 0;
ptSapContext sapContext;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
"%s", __func__);
for (i = 0; i < SAP_MAX_NUM_SESSION; i++) {
sapContext = (ptSapContext) mac->sap.sapCtxList[i].pSapContext;
if (((QDF_SAP_MODE == mac->sap.sapCtxList[i].sapPersona)
||
(QDF_P2P_GO_MODE == mac->sap.sapCtxList[i].sapPersona)) &&
(sapContext) &&
(sapContext->sapsMachine == eSAP_DFS_CAC_WAIT)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
"%s: found SAP in cac wait state", __func__);
return sapContext;
}
if (sapContext) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
"sapdfs: mode:%d intf:%d state:%d",
mac->sap.sapCtxList[i].sapPersona, i,
sapContext->sapsMachine);
}
}
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 QDF_STATUS code associated with performing the operation
QDF_STATUS_SUCCESS: Success
SIDE EFFECTS
NA
============================================================================*/
QDF_STATUS sap_close_session(tHalHandle hHal,
ptSapContext sapContext,
csr_roamSessionCloseCallback callback, bool valid)
{
QDF_STATUS qdf_status;
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
if (false == valid) {
qdf_status = sme_close_session(hHal,
sapContext->sessionId, true,
callback, NULL);
} else {
qdf_status = sme_close_session(hHal,
sapContext->sessionId, true,
callback, sapContext);
}
sapContext->isCacStartNotified = false;
sapContext->isCacEndNotified = false;
sapContext->is_chan_change_inprogress = false;
pMac->sap.sapCtxList[sapContext->sessionId].pSapContext = NULL;
sapContext->isSapSessionOpen = false;
sapContext->pre_cac_complete = false;
sapContext->is_pre_cac_on = false;
sapContext->chan_before_pre_cac = 0;
if (NULL == sap_find_valid_concurrent_session(hHal)) {
/* If timer is running then stop the timer and destory it */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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) {
qdf_mc_timer_stop(&pMac->sap.SapDfsInfo.
sap_dfs_cac_timer);
pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0;
qdf_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);
qdf_mem_zero(&pMac->sap, sizeof(pMac->sap));
}
return qdf_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 (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona)
||
(QDF_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 : QDF_STATUS.
SIDE EFFECTS
============================================================================*/
static QDF_STATUS sap_cac_start_notify(tHalHandle hHal)
{
uint8_t intf = 0;
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) {
ptSapContext pSapContext =
(ptSapContext) pMac->sap.sapCtxList[intf].pSapContext;
tCsrRoamProfile *profile;
if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona)
||
(QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona))
&& pMac->sap.sapCtxList[intf].pSapContext != NULL &&
(false == pSapContext->isCacStartNotified)) {
/* Don't start CAC for non-dfs channel, its violation */
profile = &pSapContext->csr_roamProfile;
if (!CDS_IS_DFS_CH(profile->operationChannel))
continue;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
"sapdfs: Signaling eSAP_DFS_CAC_START to HDD for sapctx[%pK]",
pSapContext);
qdf_status = sap_signal_hdd_event(pSapContext, NULL,
eSAP_DFS_CAC_START,
(void *)
eSAP_STATUS_SUCCESS);
if (QDF_STATUS_SUCCESS != qdf_status) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"In %s, failed setting isCacStartNotified on interface[%d]",
__func__, intf);
return qdf_status;
}
pSapContext->isCacStartNotified = true;
}
}
return qdf_status;
}
/**
* wlansap_update_pre_cac_end() - Update pre cac end to upper layer
* @sap_context: SAP context
* @mac: Global MAC structure
* @intf: Interface number
*
* Notifies pre cac end to upper layer
*
* Return: QDF_STATUS
*/
static QDF_STATUS wlansap_update_pre_cac_end(ptSapContext sap_context,
tpAniSirGlobal mac, uint8_t intf)
{
QDF_STATUS qdf_status;
sap_context->isCacEndNotified = true;
mac->sap.SapDfsInfo.sap_radar_found_status = false;
sap_context->sapsMachine = eSAP_STARTED;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"In %s, pre cac end notify on %d: from state %s => %s",
__func__, intf, "eSAP_DFS_CAC_WAIT",
"eSAP_STARTED");
qdf_status = sap_signal_hdd_event(sap_context,
NULL, eSAP_DFS_PRE_CAC_END,
(void *)eSAP_STATUS_SUCCESS);
if (QDF_IS_STATUS_ERROR(qdf_status)) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"In %s, pre cac notify failed on intf %d",
__func__, intf);
return qdf_status;
}
return QDF_STATUS_SUCCESS;
}
/*==========================================================================
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 : QDF_STATUS.
SIDE EFFECTS
============================================================================*/
static QDF_STATUS sap_cac_end_notify(tHalHandle hHal, tCsrRoamInfo *roamInfo)
{
uint8_t intf;
tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
QDF_STATUS qdf_status = QDF_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;
tCsrRoamProfile *profile;
if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona)
||
(QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona))
&& pMac->sap.sapCtxList[intf].pSapContext != NULL &&
(false == pSapContext->isCacEndNotified) &&
(pSapContext->sapsMachine == eSAP_DFS_CAC_WAIT)) {
pSapContext = pMac->sap.sapCtxList[intf].pSapContext;
/* Don't check CAC for non-dfs channel */
profile = &pSapContext->csr_roamProfile;
if (!CDS_IS_DFS_CH(profile->operationChannel))
continue;
/* If this is an end notification of a pre cac, the
* SAP must not start beaconing and must delete the
* temporary interface created for pre cac and switch
* the original SAP to the pre CAC channel.
*/
if (pSapContext->is_pre_cac_on) {
qdf_status = wlansap_update_pre_cac_end(
pSapContext, pMac, intf);
if (QDF_IS_STATUS_ERROR(qdf_status))
return qdf_status;
/* pre CAC is not allowed with any concurrency.
* So, we can break from here.
*/
break;
}
qdf_status = sap_signal_hdd_event(pSapContext, NULL,
eSAP_DFS_CAC_END,
(void *)
eSAP_STATUS_SUCCESS);
if (QDF_STATUS_SUCCESS != qdf_status) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"In %s, failed setting isCacEndNotified on interface[%d]",
__func__, intf);
return qdf_status;
}
pSapContext->isCacEndNotified = true;
pMac->sap.SapDfsInfo.sap_radar_found_status = false;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
"sapdfs: Start beacon request on sapctx[%pK]",
pSapContext);
/* Start beaconing on the new channel */
wlansap_start_beacon_req(pSapContext);
/* Transition from eSAP_STARTING to eSAP_STARTED
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 */
qdf_status = sap_signal_hdd_event(pSapContext, roamInfo,
eSAP_START_BSS_EVENT,
(void *)
eSAP_STATUS_SUCCESS);
if (QDF_STATUS_SUCCESS != qdf_status) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
"In %s, failed setting isCacEndNotified on interface[%d]",
__func__, intf);
return qdf_status;
}
/* Transition from eSAP_STARTING to eSAP_STARTED
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 qdf_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: QDF_STATUS
*/
static QDF_STATUS sap_fsm_state_disconnected(ptSapContext sap_ctx,
ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx,
tHalHandle hal)
{
uint32_t msg = sap_event->event;
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
if (msg == eSAP_HDD_START_INFRA_BSS) {
/*
* Transition from eSAP_DISCONNECTED to eSAP_CH_SELECT
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("new from state %s => %s: session:%d"),
"eSAP_DISCONNECTED", "eSAP_CH_SELECT",
sap_ctx->sessionId);
if (sap_ctx->isSapSessionOpen == false) {
uint32_t type, subtype;
if (sap_ctx->csr_roamProfile.csrPersona ==
QDF_P2P_GO_MODE)
qdf_status = cds_get_vdev_types(QDF_P2P_GO_MODE,
&type, &subtype);
else
qdf_status = cds_get_vdev_types(QDF_SAP_MODE,
&type,
&subtype);
if (QDF_STATUS_SUCCESS != qdf_status) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_FATAL,
"failed to get vdev type");
return QDF_STATUS_E_FAILURE;
}
qdf_status = sme_open_session(hal,
&wlansap_roam_callback,
sap_ctx, sap_ctx->self_mac_addr,
&sap_ctx->sessionId, type, subtype);
if (QDF_STATUS_SUCCESS != qdf_status) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
FL("Error: calling sme_open_session"));
return QDF_STATUS_E_FAILURE;
}
sap_ctx->isSapSessionOpen = 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.
*/
qdf_status = sap_goto_channel_sel(sap_ctx, sap_event, false,
true);
} 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;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("from state eSAP_DISCONNECTED => SAP_DFS_CAC_WAIT"));
if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running != true) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: starting dfs cac timer on sapctx[%pK]"),
sap_ctx);
sap_start_dfs_cac_timer(sap_ctx);
}
qdf_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.
*/
qdf_status = sap_goto_channel_sel(sap_ctx, sap_event, false,
false);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("in state %s, event msg %d"),
"eSAP_DISCONNECTED", msg);
}
return qdf_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: QDF_STATUS
*/
static QDF_STATUS sap_fsm_state_ch_select(ptSapContext sap_ctx,
ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx,
tHalHandle hal)
{
uint32_t msg = sap_event->event;
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
bool b_leak_chan = false;
#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION
uint8_t temp_chan;
tSapDfsNolInfo *p_nol;
#endif
if (msg == eSAP_MAC_SCAN_COMPLETE) {
#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION
temp_chan = sap_ctx->channel;
p_nol = mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList;
sap_mark_leaking_ch(sap_ctx,
sap_ctx->ch_params.ch_width, 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,
PHY_CHANNEL_BONDING_STATE_MAX) || 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 */
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_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 QDF_STATUS_E_FAULT;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("channel %d is in NOL, StartBss on new channel %d"),
sap_ctx->channel, ch);
sap_ctx->channel = ch;
cds_set_channel_params(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;
/*
* 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;
}
/*
* Transition from eSAP_CH_SELECT to eSAP_STARTING
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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;
sap_ctx->csr_roamProfile.beacon_tx_rate =
sap_ctx->beacon_tx_rate;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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);
qdf_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;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Cannot start BSS, ACS Fail"));
sap_signal_hdd_event(sap_ctx, NULL, eSAP_START_BSS_EVENT,
(void *)eSAP_STATUS_FAILURE);
} 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);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
"%s: BSS stopped when Ch select in Progress", __func__);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("in state %s, invalid event msg %d"),
"eSAP_CH_SELECT", msg);
}
return qdf_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: QDF_STATUS
*/
static QDF_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);
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
if (msg == eSAP_DFS_CHANNEL_CAC_START) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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);
qdf_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
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
"ENTERTRED CAC WAIT STATE-->eSAP_DISCONNECTING\n");
if (mac_ctx->sap.SapDfsInfo.target_channel) {
cds_set_channel_params(
mac_ctx->sap.SapDfsInfo.target_channel, 0,
&sap_ctx->ch_params);
}
for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) {
ptSapContext t_sap_ctx;
tCsrRoamProfile *profile;
t_sap_ctx = mac_ctx->sap.sapCtxList[intf].pSapContext;
if (((QDF_SAP_MODE ==
mac_ctx->sap.sapCtxList[intf].sapPersona) ||
(QDF_P2P_GO_MODE ==
mac_ctx->sap.sapCtxList[intf].sapPersona)) &&
t_sap_ctx != NULL &&
t_sap_ctx->sapsMachine != eSAP_DISCONNECTED) {
profile = &t_sap_ctx->csr_roamProfile;
if (!CDS_IS_DFS_CH(profile->operationChannel))
continue;
/* SAP to be moved to DISCONNECTING state */
t_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) {
qdf_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 */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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)) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: no sessions are valid, stopping timer"));
sap_stop_dfs_cac_timer(sap_ctx);
}
sap_ctx->sapsMachine = eSAP_DISCONNECTING;
qdf_status = sap_goto_disconnecting(sap_ctx);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("in state %s, invalid event msg %d"),
"eSAP_DFS_CAC_WAIT", msg);
}
return qdf_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: QDF_STATUS
*/
static QDF_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;
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
uint8_t is_dfs = false;
if (msg == eSAP_MAC_START_BSS_SUCCESS) {
/*
* Transition from eSAP_STARTING to eSAP_STARTED
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("from state channel = %d %s => %s ch_width %d"),
sap_ctx->channel, "eSAP_STARTING", "eSAP_STARTED",
sap_ctx->ch_params.ch_width);
sap_ctx->sapsMachine = eSAP_STARTED;
/* Action code for transition */
qdf_status = sap_signal_hdd_event(sap_ctx, roam_info,
eSAP_START_BSS_EVENT,
(void *) eSAP_STATUS_SUCCESS);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("ap_ctx->ch_params.ch_width %d, channel %d"),
sap_ctx->ch_params.ch_width,
cds_get_channel_state(sap_ctx->channel));
/*
* 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 (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) {
is_dfs = true;
} else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) {
if (cds_get_channel_state(sap_ctx->channel) ==
CHANNEL_STATE_DFS ||
cds_get_channel_state(sap_ctx->
ch_params.center_freq_seg1 -
SIR_80MHZ_START_CENTER_CH_DIFF) ==
CHANNEL_STATE_DFS)
is_dfs = true;
} else {
if (cds_get_channel_state(sap_ctx->channel) ==
CHANNEL_STATE_DFS)
is_dfs = true;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("is_dfs %d"), is_dfs);
if (is_dfs) {
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) &&
!sap_ctx->pre_cac_complete) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_HIGH,
FL("start cac timer"));
/* 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);
qdf_status = sap_cac_start_notify(hal);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_HIGH,
FL("skip cac timer"));
wlansap_start_beacon_req(sap_ctx);
}
}
} else if (msg == eSAP_MAC_START_FAILS ||
msg == eSAP_HDD_STOP_INFRA_BSS) {
/*
* Transition from eSAP_STARTING to eSAP_DISCONNECTED
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("from state %s => %s"),
"eSAP_STARTING", "eSAP_DISCONNECTED");
/* Advance outer statevar */
sap_ctx->sapsMachine = eSAP_DISCONNECTED;
qdf_status = sap_signal_hdd_event(sap_ctx, NULL,
eSAP_START_BSS_EVENT,
(void *) eSAP_STATUS_FAILURE);
qdf_status = sap_goto_disconnected(sap_ctx);
/* Close the SME session */
if (true == sap_ctx->isSapSessionOpen) {
if (QDF_STATUS_SUCCESS == sap_close_session(hal,
sap_ctx, NULL, false))
sap_ctx->isSapSessionOpen = 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;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("from state %s => %s"),
"eSAP_STARTING", "eSAP_STARTED");
/* Indicate change in the state to upper layers */
qdf_status = sap_signal_hdd_event(sap_ctx, roam_info,
eSAP_START_BSS_EVENT,
(void *)eSAP_STATUS_SUCCESS);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("in state %s, invalid event msg %d"),
"eSAP_STARTING", msg);
}
return qdf_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: QDF_STATUS
*/
static QDF_STATUS sap_fsm_state_started(ptSapContext sap_ctx,
ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx)
{
uint32_t msg = sap_event->event;
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
if (msg == eSAP_HDD_STOP_INFRA_BSS) {
/*
* Transition from eSAP_STARTED to eSAP_DISCONNECTING
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("from state %s => %s"),
"eSAP_STARTED", "eSAP_DISCONNECTING");
sap_ctx->sapsMachine = eSAP_DISCONNECTING;
qdf_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;
tCsrRoamProfile *profile;
if (((QDF_SAP_MODE ==
mac_ctx->sap.sapCtxList[intf].sapPersona) ||
(QDF_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;
/*
* Radar won't come on non-dfs channel, so
* no need to move them
*/
profile = &temp_sap_ctx->csr_roamProfile;
if (!CDS_IS_DFS_CH(profile->operationChannel))
continue;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: Sending CSAIE for sapctx[%pK]"),
temp_sap_ctx);
qdf_status = wlansap_dfs_send_csa_ie_request(
(void *) temp_sap_ctx);
}
}
} else if (eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START == msg) {
enum tQDF_ADAPTER_MODE persona;
if (!sap_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid sap_ctx"));
return qdf_status;
}
persona = mac_ctx->sap.sapCtxList[sap_ctx->sessionId].
sapPersona;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("app trigger chan switch: mode:%d vdev:%d"),
persona, sap_ctx->sessionId);
if ((QDF_SAP_MODE == persona) || (QDF_P2P_GO_MODE == persona))
qdf_status = wlansap_dfs_send_csa_ie_request(
(void *) sap_ctx);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("in state %s, invalid event msg %d"),
"eSAP_STARTED", msg);
}
return qdf_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: QDF_STATUS
*/
static QDF_STATUS sap_fsm_state_disconnecting(ptSapContext sap_ctx,
ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx,
tHalHandle hal)
{
uint32_t msg = sap_event->event;
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
if (msg == eSAP_MAC_READY_FOR_CONNECTIONS) {
/*
* Transition from eSAP_DISCONNECTING to eSAP_DISCONNECTED
* (both without substates)
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("from state %s => %s"),
"eSAP_DISCONNECTING", "eSAP_DISCONNECTED");
sap_ctx->sapsMachine = eSAP_DISCONNECTED;
/* Close the SME session */
if (true == sap_ctx->isSapSessionOpen) {
sap_ctx->isSapSessionOpen = false;
qdf_status = sap_close_session(hal, sap_ctx,
sap_roam_session_close_callback, true);
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
qdf_status = sap_signal_hdd_event(sap_ctx, NULL,
eSAP_STOP_BSS_EVENT,
(void *)eSAP_STATUS_SUCCESS);
}
}
} else if (msg == eWNI_SME_CHANNEL_CHANGE_REQ) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
FL("sapdfs: Send channel change request on sapctx[%pK]"),
sap_ctx);
/*
* Most likely, radar has been detected and SAP wants to
* change the channel
*/
qdf_status = wlansap_channel_change_request((void *) sap_ctx,
mac_ctx->sap.SapDfsInfo.target_channel);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("Sending DFS eWNI_SME_CHANNEL_CHANGE_REQ"));
} else if (msg == eWNI_SME_CHANNEL_CHANGE_RSP) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("in state %s, event msg %d result %d"),
"eSAP_DISCONNECTING ", msg, sap_event->u2);
if (sap_event->u2 == eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE)
qdf_status = sap_goto_disconnecting(sap_ctx);
} else if ((msg == eSAP_HDD_STOP_INFRA_BSS) &&
(sap_ctx->is_chan_change_inprogress)) {
/* stop bss is recieved while processing channel change */
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("in state %s, event msg %d result %d"),
"eSAP_DISCONNECTING ", msg, sap_event->u2);
qdf_status = sap_goto_disconnecting(sap_ctx);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("in state %s, invalid event msg %d"),
"eSAP_DISCONNECTING", msg);
}
return qdf_status;
}
/**
* sap_fsm() - SAP statem machine entry function
* @sap_ctx: SAP context
* @sap_event: SAP event
*
* SAP statem machine entry function
*
* Return: QDF_STATUS
*/
QDF_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 */
QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx);
tpAniSirGlobal mac_ctx;
if (NULL == hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid hal"));
return QDF_STATUS_E_FAILURE;
}
mac_ctx = PMAC_STRUCT(hal);
if (NULL == mac_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid MAC context"));
return QDF_STATUS_E_FAILURE;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
FL("sap_ctx=%pK, state_var=%d, msg=0x%x"),
sap_ctx, state_var, msg);
switch (state_var) {
case eSAP_DISCONNECTED:
qdf_status = sap_fsm_state_disconnected(sap_ctx, sap_event,
mac_ctx, hal);
break;
case eSAP_CH_SELECT:
qdf_status = sap_fsm_state_ch_select(sap_ctx, sap_event,
mac_ctx, hal);
break;
case eSAP_DFS_CAC_WAIT:
qdf_status = sap_fsm_state_dfs_cac_wait(sap_ctx, sap_event,
mac_ctx, hal);
break;
case eSAP_STARTING:
qdf_status = sap_fsm_state_starting(sap_ctx, sap_event,
mac_ctx, hal);
break;
case eSAP_STARTED:
qdf_status = sap_fsm_state_started(sap_ctx, sap_event,
mac_ctx);
break;
case eSAP_DISCONNECTING:
qdf_status = sap_fsm_state_disconnecting(sap_ctx, sap_event,
mac_ctx, hal);
break;
}
return qdf_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;
qdf_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;
qdf_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;
if (profile->pRSNReqIE) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
FL("pRSNReqIE already allocated."));
qdf_mem_free(profile->pRSNReqIE);
profile->pRSNReqIE = NULL;
}
/* set the RSN/WPA IE */
profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength;
if (pconfig_params->RSNWPAReqIELength) {
profile->pRSNReqIE =
qdf_mem_malloc(pconfig_params->RSNWPAReqIELength);
if (NULL == profile->pRSNReqIE) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
" %s Fail to alloc memory", __func__);
return eSAP_STATUS_FAILURE;
}
qdf_mem_copy(profile->pRSNReqIE, pconfig_params->RSNWPAReqIE,
pconfig_params->RSNWPAReqIELength);
profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength;
}
/* 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])
qdf_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;
if (pconfig_params->supported_rates.numRates) {
qdf_mem_copy(profile->supported_rates.rate,
pconfig_params->supported_rates.rate,
pconfig_params->supported_rates.numRates);
profile->supported_rates.numRates =
pconfig_params->supported_rates.numRates;
}
if (pconfig_params->extended_rates.numRates) {
qdf_mem_copy(profile->extended_rates.rate,
pconfig_params->extended_rates.rate,
pconfig_params->extended_rates.numRates);
profile->extended_rates.numRates =
pconfig_params->extended_rates.numRates;
}
profile->chan_switch_hostapd_rate_enabled =
pconfig_params->chan_switch_hostapd_rate_enabled;
return eSAP_STATUS_SUCCESS; /* Success. */
}
void sap_free_roam_profile(tCsrRoamProfile *profile)
{
if (profile->pRSNReqIE) {
qdf_mem_free(profile->pRSNReqIE);
profile->pRSNReqIE = NULL;
}
}
void sap_sort_mac_list(struct qdf_mac_addr *macList, uint8_t size)
{
uint8_t outer, inner;
struct qdf_mac_addr temp;
int32_t nRes = -1;
if ((NULL == macList) || (size > MAX_ACL_MAC_ADDRESS)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 =
qdf_mem_cmp((macList + inner)->bytes,
(macList + inner + 1)->bytes,
QDF_MAC_ADDR_SIZE);
if (nRes > 0) {
qdf_mem_copy(temp.bytes,
(macList + inner + 1)->bytes,
QDF_MAC_ADDR_SIZE);
qdf_mem_copy((macList + inner + 1)->bytes,
(macList + inner)->bytes,
QDF_MAC_ADDR_SIZE);
qdf_mem_copy((macList + inner)->bytes,
temp.bytes, QDF_MAC_ADDR_SIZE);
}
}
}
}
bool
sap_search_mac_list(struct qdf_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)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("either buffer is NULL or size = %d is more."), num_mac);
return false;
}
while (nStart <= nEnd) {
nMiddle = (nStart + nEnd) / 2;
nRes =
qdf_mem_cmp(&macList[nMiddle], peerMac,
QDF_MAC_ADDR_SIZE);
if (0 == nRes) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_HIGH, "index %d",
*index);
}
return true;
}
if (nRes < 0)
nStart = nMiddle + 1;
else
nEnd = nMiddle - 1;
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"search not succ");
return false;
}
void sap_add_mac_to_acl(struct qdf_mac_addr *macList,
uint8_t *size, uint8_t *peerMac)
{
int32_t nRes = -1;
int i;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"add acl entered");
if (NULL == macList || *size > MAX_ACL_MAC_ADDRESS) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
FL("either buffer is NULL or size = %d is incorrect."),
*size);
return;
}
for (i = ((*size) - 1); i >= 0; i--) {
nRes =
qdf_mem_cmp(&macList[i], peerMac, QDF_MAC_ADDR_SIZE);
if (nRes > 0) {
/* Move alphabetically greater mac addresses one index down to allow for insertion
of new mac in sorted order */
qdf_mem_copy((macList + i + 1)->bytes,
(macList + i)->bytes, QDF_MAC_ADDR_SIZE);
} else {
break;
}
}
/* This should also take care of if the element is the first to be added in the list */
qdf_mem_copy((macList + i + 1)->bytes, peerMac, QDF_MAC_ADDR_SIZE);
/* increment the list size */
(*size)++;
}
void sap_remove_mac_from_acl(struct qdf_mac_addr *macList,
uint8_t *size, uint8_t index)
{
int i;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 */
qdf_mem_copy((macList + i)->bytes, (macList + i + 1)->bytes,
QDF_MAC_ADDR_SIZE);
}
/* The last space should be made empty since all mac addesses moved one step up */
qdf_mem_zero((macList + (*size) - 1)->bytes, QDF_MAC_ADDR_SIZE);
/* reduce the list size by 1 */
(*size)--;
}
void sap_print_acl(struct qdf_mac_addr *macList, uint8_t size)
{
int i;
uint8_t *macArray;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"print acl entered");
if ((NULL == macList) || (size == 0) || (size >= MAX_ACL_MAC_ADDRESS)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"** ACL entry %i - " MAC_ADDRESS_STR, i,
MAC_ADDR_ARRAY(macArray));
}
return;
}
QDF_STATUS sap_is_peer_mac_allowed(ptSapContext sapContext, uint8_t *peerMac)
{
if (eSAP_ALLOW_ALL == sapContext->eSapMacAddrAclMode)
return QDF_STATUS_SUCCESS;
if (sap_search_mac_list
(sapContext->acceptMacList, sapContext->nAcceptMac, peerMac, NULL))
return QDF_STATUS_SUCCESS;
if (sap_search_mac_list
(sapContext->denyMacList, sapContext->nDenyMac, peerMac, NULL)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH,
"In %s, Peer " MAC_ADDRESS_STR " in deny list",
__func__, MAC_ADDR_ARRAY(peerMac));
return QDF_STATUS_E_FAILURE;
}
/* A new station CAN associate, unless in deny list. Less stringent mode */
if (eSAP_ACCEPT_UNLESS_DENIED == sapContext->eSapMacAddrAclMode)
return QDF_STATUS_SUCCESS;
/* A new station CANNOT associate, unless in accept list. More stringent mode */
if (eSAP_DENY_UNLESS_ACCEPTED == sapContext->eSapMacAddrAclMode) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 QDF_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);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 QDF_STATUS_E_FAILURE;
}
return QDF_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: QDF_STATUS
*/
static QDF_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 new_chan_count = 0;
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);
tSapChSelSpectInfo spect_info_obj = { NULL, 0 };
uint16_t ch_width;
if (NULL == hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Invalid HAL pointer from p_cds_gctx"));
*num_ch = 0;
*ch_list = NULL;
return QDF_STATUS_E_FAULT;
}
start_ch_num = sap_ctx->acs_cfg->start_ch;
end_ch_num = sap_ctx->acs_cfg->end_ch;
ch_width = sap_ctx->acs_cfg->ch_width;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("startChannel %d, EndChannel %d, ch_width %d, HW:%d"),
start_ch_num, end_ch_num, ch_width,
sap_ctx->acs_cfg->hw_mode);
wlansap_extend_to_acs_range(&start_ch_num, &end_ch_num,
&band_start_ch, &band_end_ch);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("expanded startChannel %d,EndChannel %d"),
start_ch_num, end_ch_num);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 == CHAN_ENUM_1) &&
(band_end_ch == CHAN_ENUM_14)) {
/* Set 2.4GHz upper limit to channel 9 for LTE COEX */
band_end_ch = CHAN_ENUM_9;
}
/* Allocate the max number of channel supported */
list = (uint8_t *) qdf_mem_malloc(NUM_5GHZ_CHANNELS +
NUM_24GHZ_CHANNELS);
if (NULL == list) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Unable to allocate channel list"));
*num_ch = 0;
*ch_list = NULL;
return QDF_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 > CDS_CHANNEL_NUM(loop_count)) ||
(end_ch_num < CDS_CHANNEL_NUM(loop_count)))
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 (!(((true == mac_ctx->scan.fEnableDFSChnlScan) &&
CDS_CHANNEL_STATE(loop_count)) ||
((false == mac_ctx->scan.fEnableDFSChnlScan) &&
(CHANNEL_STATE_ENABLE ==
CDS_CHANNEL_STATE(loop_count)))))
continue;
/*
* Skip the channels which are not in ACS config from user
* space
*/
if (SAP_CHANNEL_NOT_SELECTED ==
sap_channel_in_acs_channel_list(
CDS_CHANNEL_NUM(loop_count),
sap_ctx, &spect_info_obj))
continue;
/*
* If we have any 5Ghz channel in the channel list
* and bw is 40/80/160 Mhz then we don't want SAP to
* come up in 2.4Ghz as for 40Mhz, 2.4Ghz channel is
* not preferred and 80/160Mhz is not allowed for 2.4Ghz
* band. So, don't even scan on 2.4Ghz channels if bw is
* 40/80/160Mhz and channel list has any 5Ghz channel.
*/
if (end_ch_num >= CDS_CHANNEL_NUM(CHAN_ENUM_36) &&
((ch_width == CH_WIDTH_40MHZ) ||
(ch_width == CH_WIDTH_80MHZ) ||
(ch_width == CH_WIDTH_80P80MHZ) ||
(ch_width == CH_WIDTH_160MHZ))) {
if (CDS_CHANNEL_NUM(loop_count) >=
CDS_CHANNEL_NUM(CHAN_ENUM_1) &&
CDS_CHANNEL_NUM(loop_count) <=
CDS_CHANNEL_NUM(CHAN_ENUM_14))
continue;
}
#ifdef FEATURE_WLAN_CH_AVOID
for (i = 0; i < NUM_CHANNELS; i++) {
if (safe_channels[i].channelNumber ==
CDS_CHANNEL_NUM(loop_count)) {
/* Check if channel is safe */
if (true == safe_channels[i].isSafe) {
#endif
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
uint8_t ch;
ch = CDS_CHANNEL_NUM(loop_count);
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] =
CDS_CHANNEL_NUM(loop_count);
ch_count++;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO,
FL("%d %d added to ACS ch range"),
ch_count, ch);
} else {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO_HIGH,
FL("%d %d skipped from ACS ch range"),
ch_count, ch);
}
} else {
list[ch_count] =
CDS_CHANNEL_NUM(loop_count);
ch_count++;
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_INFO,
FL("%d %d added to ACS ch range"),
ch_count, ch);
}
#else
list[ch_count] = CDS_CHANNEL_NUM(loop_count);
ch_count++;
#endif
#ifdef FEATURE_WLAN_CH_AVOID
}
break;
}
}
#endif
}
for (i = 0; i < ch_count; i++) {
if (cds_is_etsi13_regdmn_srd_chan(cds_chan_to_freq(list[i]))) {
if (!sap_ctx->enable_etsi_srd_chan_support)
continue;
}
list[new_chan_count] = list[i];
new_chan_count++;
}
ch_count = new_chan_count;
if (0 == ch_count) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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))
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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;
qdf_mem_free(list);
}
for (loop_count = 0; loop_count < ch_count; loop_count++) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
FL("channel number: %d"), list[loop_count]);
}
return QDF_STATUS_SUCCESS;
}
#endif
/*
* Function for initializing list of 2.4/5 Ghz [NON-DFS/DFS]
* available channels in the current regulatory domain.
*/
static QDF_STATUS sap_get_5ghz_channel_list(ptSapContext sapContext)
{
uint8_t count = 0;
int i;
struct sir_pcl_list pcl;
QDF_STATUS status;
enum channel_state ch_state;
pcl.pcl_len = 0;
if (NULL == sapContext) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"Invalid sapContext pointer on sap_get_channel_list");
return QDF_STATUS_E_FAULT;
}
if (sapContext->SapAllChnlList.channelList) {
qdf_mem_free(sapContext->SapAllChnlList.channelList);
sapContext->SapAllChnlList.channelList = NULL;
}
sapContext->SapAllChnlList.channelList =
(tChannelInfo *) qdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN *
sizeof(tChannelInfo));
if (NULL == sapContext->SapAllChnlList.channelList) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
" Memory Allocation failed sap_get_channel_list");
return QDF_STATUS_E_NOMEM;
}
if (cds_mode_specific_connection_count(CDS_SAP_MODE, NULL) == 0) {
status = cds_get_pcl(CDS_SAP_MODE,
pcl.pcl_list, &pcl.pcl_len, pcl.weight_list,
QDF_ARRAY_SIZE(pcl.weight_list));
} else {
status = cds_get_pcl_for_existing_conn(CDS_SAP_MODE,
pcl.pcl_list, &pcl.pcl_len, pcl.weight_list,
QDF_ARRAY_SIZE(pcl.weight_list), true);
}
if (status != QDF_STATUS_SUCCESS) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"Get PCL failed");
return status;
}
for (i = 0; i <= pcl.pcl_len; i++) {
if (CDS_IS_CHANNEL_5GHZ(pcl.pcl_list[i])) {
ch_state = cds_get_channel_state(pcl.pcl_list[i]);
if (!(ch_state == CHANNEL_STATE_ENABLE ||
ch_state == CHANNEL_STATE_DFS))
continue;
sapContext->SapAllChnlList.channelList[count].channel =
pcl.pcl_list[i];
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
"%s[%d] CHANNEL = %d", __func__, __LINE__,
pcl.pcl_list[i]);
sapContext->SapAllChnlList.channelList[count].valid =
true;
count++;
}
}
sapContext->SapAllChnlList.numChannel = count;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
"%s[%d] NUMBER OF CHANNELS count = %d"
"sapContext->SapAllChnlList.numChannel = %d",
__func__, __LINE__, count,
sapContext->SapAllChnlList.numChannel);
return QDF_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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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 = true;
if (sapContext->csr_roamProfile.disableDFSChSwitch) {
return sapContext->channel;
}
/* set the Radar Found flag in SapDfsInfo */
pMac->sap.SapDfsInfo.sap_radar_found_status = true;
if (dfs_event->chan_list.nchannels > SIR_DFS_MAX_20M_SUB_CH) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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());
if (sapContext->chan_before_pre_cac) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("sapdfs: set chan before pre cac %d as target chan"),
sapContext->chan_before_pre_cac);
return sapContext->chan_before_pre_cac;
}
/*
* (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);
}
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"In %s invalid hHal", __func__);
return;
}
pMac = PMAC_STRUCT(hHal);
sapContext = sap_find_cac_wait_session(hHal);
if (NULL == sapContext) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"%s: no SAP contexts in wait state", __func__);
return;
}
/*
* SAP may not be in CAC wait state, when the timer runs out.
* if following flag is set, then timer is in initialized state,
* destroy timer here.
*/
if (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running == true) {
qdf_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
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
"sapdfs: Sending eSAP_DFS_CHANNEL_CAC_END for target_channel = %d on sapctx[%pK]",
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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"In %s invalid hHal", __func__);
return 0;
}
pMac = PMAC_STRUCT(hHal);
if (QDF_TIMER_STATE_RUNNING !=
qdf_mc_timer_get_current_state(&pMac->sap.SapDfsInfo.
sap_dfs_cac_timer)) {
return 0;
}
qdf_mc_timer_stop(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer);
pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0;
qdf_mc_timer_destroy(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer);
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;
}
/**
* sap_update_cac_duration() - get cac duration
* @sap_ctx: sap context
* @cac_timeout: cac duration
*
* This function will update cac_timeout based on sap channels.
*
* Return: None
*/
static void sap_update_cac_duration(ptSapContext sap_ctx, uint32_t *cac_timeout)
{
int i;
enum dfs_region dfs_region;
uint8_t channels[MAX_BONDED_CHANNELS];
uint8_t num_channels;
struct ch_params_s *ch_params = &sap_ctx->ch_params;
*cac_timeout = DEFAULT_CAC_TIMEOUT;
cds_get_dfs_region(&dfs_region);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("sapdfs: dfs_region=%d, chwidth=%d, seg0=%d, seg1=%d"),
dfs_region, ch_params->ch_width,
ch_params->center_freq_seg0, ch_params->center_freq_seg1);
if (dfs_region != DFS_ETSI_REGION) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("sapdfs: defult cac duration"));
return;
}
if (sap_is_channel_bonding_etsi_weather_channel(sap_ctx)) {
*cac_timeout = ETSI_WEATHER_CH_CAC_TIMEOUT;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("sapdfs: bonding_etsi_weather_channel"));
return;
}
qdf_mem_zero(channels, sizeof(channels));
num_channels = sap_ch_params_to_bonding_channels(ch_params, channels);
for (i = 0; i < num_channels; i++) {
if (IS_ETSI_WEATHER_CH(channels[i])) {
*cac_timeout = ETSI_WEATHER_CH_CAC_TIMEOUT;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("sapdfs: ch=%d is etsi weather channel"),
channels[i]);
return;
}
}
}
/*
* Function to start the DFS CAC Timer
* when SAP is started on a DFS channel
*/
int sap_start_dfs_cac_timer(ptSapContext sap_ctx)
{
QDF_STATUS status;
uint32_t cac_timeout;
tHalHandle hal = NULL;
tpAniSirGlobal mac = NULL;
if (!sap_ctx) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("null sap_ctx"));
return 0;
}
hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx);
if (!hal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("null hal"));
return 0;
}
mac = PMAC_STRUCT(hal);
if (mac->sap.SapDfsInfo.ignore_cac) {
/*
* If User has set to ignore the CAC
* so, continue without CAC Timer.
*/
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO,
FL("sapdfs: iqnore cac is set"));
return 2;
}
sap_update_cac_duration(sap_ctx, &cac_timeout);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED,
"sapdfs: SAP_DFS_CHANNEL_CAC_START on CH - %d, CAC TIMEOUT - %d sec",
sap_ctx->channel, cac_timeout / 1000);
qdf_mc_timer_init(&mac->sap.SapDfsInfo.sap_dfs_cac_timer,
QDF_TIMER_TYPE_SW,
sap_dfs_cac_timer_callback, (void *) hal);
/*Start the CAC timer */
status =
qdf_mc_timer_start(&mac->sap.SapDfsInfo.sap_dfs_cac_timer,
cac_timeout);
if (status == QDF_STATUS_SUCCESS) {
mac->sap.SapDfsInfo.is_dfs_cac_timer_running = true;
return 1;
} else {
mac->sap.SapDfsInfo.is_dfs_cac_timer_running = false;
qdf_mc_timer_destroy(&mac->sap.SapDfsInfo.sap_dfs_cac_timer);
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
FL("Failed to start cac timer"));
return 0;
}
}
/*
* This function initializes the NOL list
* parameters required to track the radar
* found DFS channels in the current Reg. Domain .
*/
QDF_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) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"Invalid sapContext pointer on sap_init_dfs_channel_nol_list");
return QDF_STATUS_E_FAULT;
}
hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx);
if (NULL == hHal) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
"In %s invalid hHal", __func__);
return QDF_STATUS_E_FAULT;
}
pMac = PMAC_STRUCT(hHal);
/* to indicate hdd to get cnss dfs nol */
if (QDF_STATUS_SUCCESS == sap_signal_hdd_event(sapContext, NULL,
eSAP_DFS_NOL_GET,
(void *)
eSAP_STATUS_SUCCESS)) {
bFound = true;
}
for (i = CHAN_ENUM_36; i <= CHAN_ENUM_165; i++) {
if (CDS_CHANNEL_STATE(i) == CHANNEL_STATE_DFS) {
/* if dfs nol is not found, initialize it */
if (!bFound) {
pMac->sap.SapDfsInfo.sapDfsChannelNolList[count]
.dfs_channel_number =
CDS_CHANNEL_NUM(i);
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_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;
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW,
"%s[%d] NUMBER OF DFS CHANNELS = %d",
__func__, __LINE__,
pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels);
return QDF_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 (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona)
||
(QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona))
&& pMac->sap.sapCtxList[intf].pSapContext != NULL) {
intf_count++;
}
}
return intf_count;
}
/**
* is_concurrent_sap_ready_for_channel_change() - to check all saps are ready
* for channel change
* @hHal: HAL pointer
* @sapContext: sap context for which this function has been called
*
* This function will find the concurrent sap context apart from
* passed sap context and return its channel change ready status
*
*
* Return: true if other SAP personas are ready to channel switch else false
*/
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 (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona)
||
(QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona))
&& pMac->sap.sapCtxList[intf].pSapContext != NULL) {
pSapContext =
(ptSapContext) pMac->sap.sapCtxList[intf].
pSapContext;
if (pSapContext == sapContext) {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
FL("sapCtx matched [%pK]"),
sapContext);
continue;
} else {
QDF_TRACE(QDF_MODULE_ID_SAP,
QDF_TRACE_LEVEL_ERROR,
FL
("concurrent sapCtx[%pK] didn't matche with [%pK]"),
pSapContext, sapContext);
return pSapContext->is_sap_ready_for_chnl_chng;
}
}
}
return false;
}
/**
* sap_is_conc_sap_doing_scc_dfs() - check if conc SAPs are doing SCC DFS
* @hal: pointer to hal
* @sap_context: current SAP persona's channel
*
* If provided SAP's channel is DFS then Loop through each SAP or GO persona and
* check if other beaconing entity's channel is same DFS channel. If they are
* same then concurrent sap is doing SCC DFS.
*
* Return: true if two or more beaconing entitity doing SCC DFS else false
*/
bool sap_is_conc_sap_doing_scc_dfs(tHalHandle hal, ptSapContext given_sapctx)
{
tpAniSirGlobal mac = PMAC_STRUCT(hal);
ptSapContext sap_ctx;
uint8_t intf = 0, scc_dfs_counter = 0;
/*
* current SAP persona's channel itself is not DFS, so no need to check
* what other persona's channel is
*/
if (!CDS_IS_DFS_CH(given_sapctx->csr_roamProfile.operationChannel)) {
QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
FL("skip this loop as provided channel is non-dfs"));
return false;
}
for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) {
if ((QDF_SAP_MODE != mac->sap.sapCtxList[intf].sapPersona) &&
(QDF_P2P_GO_MODE != mac->sap.sapCtxList[intf].sapPersona))
continue;
if (!mac->sap.sapCtxList[intf].pSapContext)
continue;
sap_ctx = (ptSapContext) mac->sap.sapCtxList[intf].pSapContext;
/* if same SAP contexts then skip to next context */
if (sap_ctx == given_sapctx)
continue;
if (given_sapctx->csr_roamProfile.operationChannel ==
sap_ctx->csr_roamProfile.operationChannel)
scc_dfs_counter++;
}
/* Found atleast two of the beaconing entities doing SCC DFS */
if (scc_dfs_counter)
return true;
return false;
}