1 /* 2 * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * 22 * This file dph_hash_table.cc implements the member functions of 23 * DPH hash table class. 24 * 25 * Author: Sandesh Goel 26 * Date: 02/25/02 27 * History:- 28 * Date Modified by Modification Information 29 * -------------------------------------------------------------------- 30 * 31 */ 32 #include "cds_api.h" 33 #include "sch_api.h" 34 #include "dph_global.h" 35 #include "lim_api.h" 36 #include "wma_if.h" 37 #include "wlan_mlme_api.h" 38 dph_hash_table_init(struct mac_context * mac,struct dph_hash_table * hash_table)39 void dph_hash_table_init(struct mac_context *mac, 40 struct dph_hash_table *hash_table) 41 { 42 uint16_t i; 43 44 for (i = 0; i < hash_table->size; i++) { 45 hash_table->pHashTable[i] = 0; 46 } 47 48 for (i = 0; i < hash_table->size; i++) { 49 hash_table->pDphNodeArray[i].valid = 0; 50 hash_table->pDphNodeArray[i].added = 0; 51 hash_table->pDphNodeArray[i].assocId = i; 52 } 53 54 } 55 56 /* --------------------------------------------------------------------- */ 57 /** 58 * hash_function 59 * 60 * FUNCTION: 61 * Hashing function 62 * 63 * LOGIC: 64 * 65 * ASSUMPTIONS: 66 * 67 * NOTE: 68 * 69 * @param staAddr MAC address of the station 70 * @return None 71 */ 72 hash_function(struct mac_context * mac,uint8_t staAddr[],uint16_t numSta)73 static uint16_t hash_function(struct mac_context *mac, uint8_t staAddr[], 74 uint16_t numSta) 75 { 76 int i; 77 uint16_t sum = 0; 78 79 for (i = 0; i < 6; i++) 80 sum += staAddr[i]; 81 82 return sum % numSta; 83 } 84 85 /* --------------------------------------------------------------------- */ 86 /** 87 * dph_lookup_hash_entry 88 * 89 * FUNCTION: 90 * Look up an entry in hash table 91 * 92 * LOGIC: 93 * 94 * ASSUMPTIONS: 95 * 96 * NOTE: 97 * 98 * @param staAddr MAC address of the station 99 * @param pStaId pointer to the Station ID assigned to the station 100 * @return pointer to STA hash entry if lookup was a success \n 101 * NULL if lookup was a failure 102 */ 103 dph_lookup_hash_entry(struct mac_context * mac,uint8_t staAddr[],uint16_t * pAssocId,struct dph_hash_table * hash_table)104 tpDphHashNode dph_lookup_hash_entry(struct mac_context *mac, uint8_t staAddr[], 105 uint16_t *pAssocId, 106 struct dph_hash_table *hash_table) 107 { 108 tpDphHashNode ptr = NULL; 109 uint16_t index = hash_function(mac, staAddr, hash_table->size); 110 111 if (!hash_table->pHashTable) { 112 pe_err("pHashTable is NULL"); 113 return ptr; 114 } 115 116 for (ptr = hash_table->pHashTable[index]; ptr; ptr = ptr->next) { 117 if (dph_compare_mac_addr(staAddr, ptr->staAddr)) { 118 *pAssocId = ptr->assocId; 119 break; 120 } 121 } 122 return ptr; 123 } 124 125 /* --------------------------------------------------------------------- */ 126 /** 127 * dph_get_hash_entry 128 * 129 * FUNCTION: 130 * Get a pointer to the hash node 131 * 132 * LOGIC: 133 * 134 * ASSUMPTIONS: 135 * 136 * NOTE: 137 * 138 * @param staId Station ID 139 * @return pointer to STA hash entry if lookup was a success \n 140 * NULL if lookup was a failure 141 */ 142 dph_get_hash_entry(struct mac_context * mac,uint16_t peerIdx,struct dph_hash_table * hash_table)143 tpDphHashNode dph_get_hash_entry(struct mac_context *mac, uint16_t peerIdx, 144 struct dph_hash_table *hash_table) 145 { 146 if (peerIdx < hash_table->size) { 147 if (hash_table->pDphNodeArray[peerIdx].added) 148 return &hash_table->pDphNodeArray[peerIdx]; 149 else 150 return NULL; 151 } else 152 return NULL; 153 154 } 155 get_node(struct mac_context * mac,uint8_t assocId,struct dph_hash_table * hash_table)156 static inline tpDphHashNode get_node(struct mac_context *mac, uint8_t assocId, 157 struct dph_hash_table *hash_table) 158 { 159 return &hash_table->pDphNodeArray[assocId]; 160 } 161 162 /** ------------------------------------------------------------- 163 \fn dph_init_sta_state 164 \brief Initialize STA state. this function saves the staId from the current entry in the DPH table with given assocId 165 \ if validStaIdx flag is set. Otherwise it sets the staId to invalid. 166 \param struct mac_context * mac 167 \param tSirMacAddr staAddr 168 \param uint16_t assocId 169 \param uint8_t validStaIdx - true ==> the staId in the DPH entry with given assocId is valid and restore it back. 170 \ false ==> set the staId to invalid. 171 \return tpDphHashNode - DPH hash node if found. 172 -------------------------------------------------------------*/ 173 dph_init_sta_state(struct mac_context * mac,tSirMacAddr staAddr,uint16_t assocId,struct dph_hash_table * hash_table)174 tpDphHashNode dph_init_sta_state(struct mac_context *mac, tSirMacAddr staAddr, 175 uint16_t assocId, 176 struct dph_hash_table *hash_table) 177 { 178 tpDphHashNode sta, pnext; 179 180 if (assocId >= hash_table->size) { 181 pe_err("Invalid Assoc Id %d", assocId); 182 return NULL; 183 } 184 185 sta = get_node(mac, (uint8_t) assocId, hash_table); 186 pnext = sta->next; 187 188 /* Clear the STA node except for the next pointer */ 189 qdf_mem_zero((uint8_t *)sta, sizeof(tDphHashNode)); 190 sta->next = pnext; 191 192 /* Initialize the assocId */ 193 sta->assocId = assocId; 194 195 /* Initialize STA mac address */ 196 qdf_mem_copy(sta->staAddr, staAddr, sizeof(tSirMacAddr)); 197 198 sta->added = 1; 199 sta->is_disassoc_deauth_in_progress = 0; 200 sta->sta_deletion_in_progress = false; 201 sta->valid = 1; 202 sta->is_key_installed = 0; 203 return sta; 204 } 205 206 /* --------------------------------------------------------------------- */ 207 /** 208 * dph_add_hash_entry 209 * 210 * FUNCTION: 211 * Add entry to hash table 212 * 213 * LOGIC: 214 * 215 * ASSUMPTIONS: 216 * 217 * NOTE: 218 * 219 * @param staAddr MAC address of the station 220 * @param staId Station ID assigned to the station 221 * @return Pointer to STA hash entry 222 */ 223 dph_add_hash_entry(struct mac_context * mac,tSirMacAddr staAddr,uint16_t assocId,struct dph_hash_table * hash_table)224 tpDphHashNode dph_add_hash_entry(struct mac_context *mac, tSirMacAddr staAddr, 225 uint16_t assocId, 226 struct dph_hash_table *hash_table) 227 { 228 tpDphHashNode ptr, node; 229 uint16_t index = hash_function(mac, staAddr, hash_table->size); 230 231 pe_debug("assocId: %d index: %d STA addr: "QDF_MAC_ADDR_FMT, 232 assocId, index, QDF_MAC_ADDR_REF(staAddr)); 233 234 if (assocId >= hash_table->size) { 235 pe_err("invalid STA id %d", assocId); 236 return NULL; 237 } 238 239 if (hash_table->pDphNodeArray[assocId].added) { 240 pe_err("already added STA %d", assocId); 241 return NULL; 242 } 243 244 for (ptr = hash_table->pHashTable[index]; ptr; ptr = ptr->next) { 245 if (ptr == ptr->next) { 246 pe_err("Infinite Loop"); 247 return NULL; 248 } 249 250 if (dph_compare_mac_addr(staAddr, ptr->staAddr) 251 || ptr->assocId == assocId) 252 break; 253 } 254 255 if (ptr) { 256 /* Duplicate entry */ 257 pe_err("assocId %d hashIndex %d entry exists", 258 assocId, index); 259 return NULL; 260 } else { 261 if (dph_init_sta_state 262 (mac, staAddr, assocId, hash_table) == NULL) { 263 pe_err("could not Init STA id: %d", assocId); 264 return NULL; 265 } 266 /* Add the node to the link list */ 267 hash_table->pDphNodeArray[assocId].next = 268 hash_table->pHashTable[index]; 269 hash_table->pHashTable[index] = 270 &hash_table->pDphNodeArray[assocId]; 271 272 node = hash_table->pHashTable[index]; 273 return node; 274 } 275 } 276 277 /* --------------------------------------------------------------------- */ 278 /** 279 * dph_delete_hash_entry 280 * 281 * FUNCTION: 282 * Delete entry from hash table 283 * 284 * LOGIC: 285 * 286 * ASSUMPTIONS: 287 * 288 * NOTE: 289 * 290 * @param staAddr MAC address of the station 291 * @param staId Station ID assigned to the station 292 * @return QDF_STATUS_SUCCESS if successful, 293 * QDF_STATUS_E_FAILURE otherwise 294 */ 295 dph_delete_hash_entry(struct mac_context * mac,tSirMacAddr staAddr,uint16_t assocId,struct dph_hash_table * hash_table)296 QDF_STATUS dph_delete_hash_entry(struct mac_context *mac, tSirMacAddr staAddr, 297 uint16_t assocId, 298 struct dph_hash_table *hash_table) 299 { 300 tpDphHashNode ptr, prev; 301 uint16_t index = hash_function(mac, staAddr, hash_table->size); 302 303 pe_debug("assocId: %d index: %d STA addr: "QDF_MAC_ADDR_FMT, 304 assocId, index, QDF_MAC_ADDR_REF(staAddr)); 305 306 if (assocId >= hash_table->size) { 307 pe_err("invalid STA id %d", assocId); 308 return QDF_STATUS_E_FAILURE; 309 } 310 311 if (hash_table->pDphNodeArray[assocId].added == 0) { 312 pe_err("STA %d never added", assocId); 313 return QDF_STATUS_E_FAILURE; 314 } 315 316 for (prev = 0, ptr = hash_table->pHashTable[index]; 317 ptr; prev = ptr, ptr = ptr->next) { 318 if (dph_compare_mac_addr(staAddr, ptr->staAddr)) 319 break; 320 if (prev == ptr) { 321 pe_err("Infinite Loop"); 322 return QDF_STATUS_E_FAILURE; 323 } 324 } 325 326 if (ptr) { 327 /* / Delete the entry after invalidating it */ 328 ptr->valid = 0; 329 memset(ptr->staAddr, 0, sizeof(ptr->staAddr)); 330 if (prev == 0) 331 hash_table->pHashTable[index] = ptr->next; 332 else 333 prev->next = ptr->next; 334 ptr->added = 0; 335 ptr->is_disassoc_deauth_in_progress = 0; 336 ptr->sta_deletion_in_progress = false; 337 ptr->ocv_enabled = 0; 338 ptr->last_ocv_done_freq = 0; 339 ptr->next = 0; 340 } else { 341 pe_err("Entry not present STA addr: "QDF_MAC_ADDR_FMT, 342 QDF_MAC_ADDR_REF(staAddr)); 343 return QDF_STATUS_E_FAILURE; 344 } 345 346 return QDF_STATUS_SUCCESS; 347 } 348 349 350