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