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