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