1 // SPDX-License-Identifier: GPL-2.0 2 /****************************************************************************** 3 * rtl871x_sta_mgt.c 4 * 5 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 6 * Linux device driver for RTL8192SU 7 * 8 * Modifications for inclusion into the Linux staging tree are 9 * Copyright(c) 2010 Larry Finger. All rights reserved. 10 * 11 * Contact information: 12 * WLAN FAE <wlanfae@realtek.com> 13 * Larry Finger <Larry.Finger@lwfinger.net> 14 * 15 ******************************************************************************/ 16 17 #define _RTL871X_STA_MGT_C_ 18 19 #include "osdep_service.h" 20 #include "drv_types.h" 21 #include "recv_osdep.h" 22 #include "xmit_osdep.h" 23 #include "sta_info.h" 24 25 static void _init_stainfo(struct sta_info *psta) 26 { 27 memset((u8 *)psta, 0, sizeof(struct sta_info)); 28 spin_lock_init(&psta->lock); 29 INIT_LIST_HEAD(&psta->list); 30 INIT_LIST_HEAD(&psta->hash_list); 31 _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); 32 _r8712_init_sta_recv_priv(&psta->sta_recvpriv); 33 INIT_LIST_HEAD(&psta->asoc_list); 34 INIT_LIST_HEAD(&psta->auth_list); 35 } 36 37 u32 _r8712_init_sta_priv(struct sta_priv *pstapriv) 38 { 39 struct sta_info *psta; 40 s32 i; 41 42 pstapriv->pallocated_stainfo_buf = kmalloc(sizeof(struct sta_info) * 43 NUM_STA + 4, GFP_ATOMIC); 44 if (!pstapriv->pallocated_stainfo_buf) 45 return _FAIL; 46 pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - 47 ((addr_t)(pstapriv->pallocated_stainfo_buf) & 3); 48 _init_queue(&pstapriv->free_sta_queue); 49 spin_lock_init(&pstapriv->sta_hash_lock); 50 pstapriv->asoc_sta_count = 0; 51 _init_queue(&pstapriv->sleep_q); 52 _init_queue(&pstapriv->wakeup_q); 53 psta = (struct sta_info *)(pstapriv->pstainfo_buf); 54 for (i = 0; i < NUM_STA; i++) { 55 _init_stainfo(psta); 56 INIT_LIST_HEAD(&(pstapriv->sta_hash[i])); 57 list_add_tail(&psta->list, &pstapriv->free_sta_queue.queue); 58 psta++; 59 } 60 INIT_LIST_HEAD(&pstapriv->asoc_list); 61 INIT_LIST_HEAD(&pstapriv->auth_list); 62 return _SUCCESS; 63 } 64 65 /* this function is used to free the memory of lock || sema for all stainfos */ 66 static void mfree_all_stainfo(struct sta_priv *pstapriv) 67 { 68 unsigned long irqL; 69 struct list_head *plist, *phead; 70 71 spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); 72 phead = &pstapriv->free_sta_queue.queue; 73 plist = phead->next; 74 while (!end_of_queue_search(phead, plist)) 75 plist = plist->next; 76 77 spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); 78 } 79 80 u32 _r8712_free_sta_priv(struct sta_priv *pstapriv) 81 { 82 if (pstapriv) { 83 /* be done before free sta_hash_lock */ 84 mfree_all_stainfo(pstapriv); 85 kfree(pstapriv->pallocated_stainfo_buf); 86 } 87 return _SUCCESS; 88 } 89 90 struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) 91 { 92 s32 index; 93 struct list_head *phash_list; 94 struct sta_info *psta; 95 struct __queue *pfree_sta_queue; 96 struct recv_reorder_ctrl *preorder_ctrl; 97 int i = 0; 98 u16 wRxSeqInitialValue = 0xffff; 99 unsigned long flags; 100 101 pfree_sta_queue = &pstapriv->free_sta_queue; 102 spin_lock_irqsave(&pfree_sta_queue->lock, flags); 103 psta = list_first_entry_or_null(&pfree_sta_queue->queue, 104 struct sta_info, list); 105 if (psta) { 106 list_del_init(&psta->list); 107 _init_stainfo(psta); 108 memcpy(psta->hwaddr, hwaddr, ETH_ALEN); 109 index = wifi_mac_hash(hwaddr); 110 if (index >= NUM_STA) { 111 psta = NULL; 112 goto exit; 113 } 114 phash_list = &pstapriv->sta_hash[index]; 115 list_add_tail(&psta->hash_list, phash_list); 116 pstapriv->asoc_sta_count++; 117 118 /* For the SMC router, the sequence number of first packet of WPS handshake 119 * will be 0. In this case, this packet will be dropped by recv_decache function 120 * if we use the 0x00 as the default value for tid_rxseq variable. So, we 121 * initialize the tid_rxseq variable as the 0xffff. 122 */ 123 for (i = 0; i < 16; i++) 124 memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], 125 &wRxSeqInitialValue, 2); 126 /* for A-MPDU Rx reordering buffer control */ 127 for (i = 0; i < 16; i++) { 128 preorder_ctrl = &psta->recvreorder_ctrl[i]; 129 preorder_ctrl->padapter = pstapriv->padapter; 130 preorder_ctrl->indicate_seq = 0xffff; 131 preorder_ctrl->wend_b = 0xffff; 132 preorder_ctrl->wsize_b = 64; 133 _init_queue(&preorder_ctrl->pending_recvframe_queue); 134 r8712_init_recv_timer(preorder_ctrl); 135 } 136 } 137 exit: 138 spin_unlock_irqrestore(&pfree_sta_queue->lock, flags); 139 return psta; 140 } 141 142 /* using pstapriv->sta_hash_lock to protect */ 143 void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta) 144 { 145 int i; 146 unsigned long irqL0; 147 struct __queue *pfree_sta_queue; 148 struct recv_reorder_ctrl *preorder_ctrl; 149 struct sta_xmit_priv *pstaxmitpriv; 150 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 151 struct sta_priv *pstapriv = &padapter->stapriv; 152 153 if (psta == NULL) 154 return; 155 pfree_sta_queue = &pstapriv->free_sta_queue; 156 pstaxmitpriv = &psta->sta_xmitpriv; 157 spin_lock_irqsave(&(pxmitpriv->vo_pending.lock), irqL0); 158 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); 159 list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); 160 spin_unlock_irqrestore(&(pxmitpriv->vo_pending.lock), irqL0); 161 spin_lock_irqsave(&(pxmitpriv->vi_pending.lock), irqL0); 162 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); 163 list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); 164 spin_unlock_irqrestore(&(pxmitpriv->vi_pending.lock), irqL0); 165 spin_lock_irqsave(&(pxmitpriv->bk_pending.lock), irqL0); 166 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); 167 list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); 168 spin_unlock_irqrestore(&(pxmitpriv->bk_pending.lock), irqL0); 169 spin_lock_irqsave(&(pxmitpriv->be_pending.lock), irqL0); 170 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); 171 list_del_init(&(pstaxmitpriv->be_q.tx_pending)); 172 spin_unlock_irqrestore(&(pxmitpriv->be_pending.lock), irqL0); 173 list_del_init(&psta->hash_list); 174 pstapriv->asoc_sta_count--; 175 /* re-init sta_info; 20061114 */ 176 _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); 177 _r8712_init_sta_recv_priv(&psta->sta_recvpriv); 178 /* for A-MPDU Rx reordering buffer control, 179 * cancel reordering_ctrl_timer 180 */ 181 for (i = 0; i < 16; i++) { 182 preorder_ctrl = &psta->recvreorder_ctrl[i]; 183 del_timer(&preorder_ctrl->reordering_ctrl_timer); 184 } 185 spin_lock(&(pfree_sta_queue->lock)); 186 /* insert into free_sta_queue; 20061114 */ 187 list_add_tail(&psta->list, &pfree_sta_queue->queue); 188 spin_unlock(&(pfree_sta_queue->lock)); 189 } 190 191 /* free all stainfo which in sta_hash[all] */ 192 void r8712_free_all_stainfo(struct _adapter *padapter) 193 { 194 unsigned long irqL; 195 struct list_head *plist, *phead; 196 s32 index; 197 struct sta_info *psta = NULL; 198 struct sta_priv *pstapriv = &padapter->stapriv; 199 struct sta_info *pbcmc_stainfo = r8712_get_bcmc_stainfo(padapter); 200 201 if (pstapriv->asoc_sta_count == 1) 202 return; 203 spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); 204 for (index = 0; index < NUM_STA; index++) { 205 phead = &(pstapriv->sta_hash[index]); 206 plist = phead->next; 207 while (!end_of_queue_search(phead, plist)) { 208 psta = container_of(plist, 209 struct sta_info, hash_list); 210 plist = plist->next; 211 if (pbcmc_stainfo != psta) 212 r8712_free_stainfo(padapter, psta); 213 } 214 } 215 spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); 216 } 217 218 /* any station allocated can be searched by hash list */ 219 struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) 220 { 221 unsigned long irqL; 222 struct list_head *plist, *phead; 223 struct sta_info *psta = NULL; 224 u32 index; 225 226 if (hwaddr == NULL) 227 return NULL; 228 index = wifi_mac_hash(hwaddr); 229 spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); 230 phead = &(pstapriv->sta_hash[index]); 231 plist = phead->next; 232 while (!end_of_queue_search(phead, plist)) { 233 psta = container_of(plist, struct sta_info, hash_list); 234 if ((!memcmp(psta->hwaddr, hwaddr, ETH_ALEN))) { 235 /* if found the matched address */ 236 break; 237 } 238 psta = NULL; 239 plist = plist->next; 240 } 241 spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); 242 return psta; 243 } 244 245 void r8712_init_bcmc_stainfo(struct _adapter *padapter) 246 { 247 unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 248 struct sta_priv *pstapriv = &padapter->stapriv; 249 250 r8712_alloc_stainfo(pstapriv, bcast_addr); 251 } 252 253 struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter) 254 { 255 struct sta_priv *pstapriv = &padapter->stapriv; 256 u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 257 258 return r8712_get_stainfo(pstapriv, bc_addr); 259 } 260 261 262 u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr) 263 { 264 return true; 265 } 266