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