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 37 static 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 49 u32 _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) 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 */ 78 static void mfree_all_stainfo(struct sta_priv *pstapriv) 79 { 80 unsigned long irqL; 81 struct list_head *plist, *phead; 82 83 spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); 84 phead = &pstapriv->free_sta_queue.queue; 85 plist = phead->next; 86 while (!end_of_queue_search(phead, plist)) 87 plist = plist->next; 88 89 spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); 90 } 91 92 u32 _r8712_free_sta_priv(struct sta_priv *pstapriv) 93 { 94 if (pstapriv) { 95 /* be done before free sta_hash_lock */ 96 mfree_all_stainfo(pstapriv); 97 kfree(pstapriv->pallocated_stainfo_buf); 98 } 99 return _SUCCESS; 100 } 101 102 struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) 103 { 104 s32 index; 105 struct list_head *phash_list; 106 struct sta_info *psta; 107 struct __queue *pfree_sta_queue; 108 struct recv_reorder_ctrl *preorder_ctrl; 109 int i = 0; 110 u16 wRxSeqInitialValue = 0xffff; 111 unsigned long flags; 112 113 pfree_sta_queue = &pstapriv->free_sta_queue; 114 spin_lock_irqsave(&pfree_sta_queue->lock, flags); 115 psta = list_first_entry_or_null(&pfree_sta_queue->queue, 116 struct sta_info, list); 117 if (psta) { 118 list_del_init(&psta->list); 119 _init_stainfo(psta); 120 memcpy(psta->hwaddr, hwaddr, ETH_ALEN); 121 index = wifi_mac_hash(hwaddr); 122 if (index >= NUM_STA) { 123 psta = NULL; 124 goto exit; 125 } 126 phash_list = &pstapriv->sta_hash[index]; 127 list_add_tail(&psta->hash_list, phash_list); 128 pstapriv->asoc_sta_count++; 129 130 /* For the SMC router, the sequence number of first packet of WPS handshake 131 * will be 0. In this case, this packet will be dropped by recv_decache function 132 * if we use the 0x00 as the default value for tid_rxseq variable. So, we 133 * initialize the tid_rxseq variable as the 0xffff. 134 */ 135 for (i = 0; i < 16; i++) 136 memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], 137 &wRxSeqInitialValue, 2); 138 /* for A-MPDU Rx reordering buffer control */ 139 for (i = 0; i < 16; i++) { 140 preorder_ctrl = &psta->recvreorder_ctrl[i]; 141 preorder_ctrl->padapter = pstapriv->padapter; 142 preorder_ctrl->indicate_seq = 0xffff; 143 preorder_ctrl->wend_b = 0xffff; 144 preorder_ctrl->wsize_b = 64; 145 _init_queue(&preorder_ctrl->pending_recvframe_queue); 146 r8712_init_recv_timer(preorder_ctrl); 147 } 148 } 149 exit: 150 spin_unlock_irqrestore(&pfree_sta_queue->lock, flags); 151 return psta; 152 } 153 154 /* using pstapriv->sta_hash_lock to protect */ 155 void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta) 156 { 157 int i; 158 unsigned long irqL0; 159 struct __queue *pfree_sta_queue; 160 struct recv_reorder_ctrl *preorder_ctrl; 161 struct sta_xmit_priv *pstaxmitpriv; 162 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 163 struct sta_priv *pstapriv = &padapter->stapriv; 164 165 if (psta == NULL) 166 return; 167 pfree_sta_queue = &pstapriv->free_sta_queue; 168 pstaxmitpriv = &psta->sta_xmitpriv; 169 spin_lock_irqsave(&(pxmitpriv->vo_pending.lock), irqL0); 170 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); 171 list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); 172 spin_unlock_irqrestore(&(pxmitpriv->vo_pending.lock), irqL0); 173 spin_lock_irqsave(&(pxmitpriv->vi_pending.lock), irqL0); 174 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); 175 list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); 176 spin_unlock_irqrestore(&(pxmitpriv->vi_pending.lock), irqL0); 177 spin_lock_irqsave(&(pxmitpriv->bk_pending.lock), irqL0); 178 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); 179 list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); 180 spin_unlock_irqrestore(&(pxmitpriv->bk_pending.lock), irqL0); 181 spin_lock_irqsave(&(pxmitpriv->be_pending.lock), irqL0); 182 r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); 183 list_del_init(&(pstaxmitpriv->be_q.tx_pending)); 184 spin_unlock_irqrestore(&(pxmitpriv->be_pending.lock), irqL0); 185 list_del_init(&psta->hash_list); 186 pstapriv->asoc_sta_count--; 187 /* re-init sta_info; 20061114 */ 188 _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); 189 _r8712_init_sta_recv_priv(&psta->sta_recvpriv); 190 /* for A-MPDU Rx reordering buffer control, 191 * cancel reordering_ctrl_timer 192 */ 193 for (i = 0; i < 16; i++) { 194 preorder_ctrl = &psta->recvreorder_ctrl[i]; 195 del_timer(&preorder_ctrl->reordering_ctrl_timer); 196 } 197 spin_lock(&(pfree_sta_queue->lock)); 198 /* insert into free_sta_queue; 20061114 */ 199 list_add_tail(&psta->list, &pfree_sta_queue->queue); 200 spin_unlock(&(pfree_sta_queue->lock)); 201 } 202 203 /* free all stainfo which in sta_hash[all] */ 204 void r8712_free_all_stainfo(struct _adapter *padapter) 205 { 206 unsigned long irqL; 207 struct list_head *plist, *phead; 208 s32 index; 209 struct sta_info *psta = NULL; 210 struct sta_priv *pstapriv = &padapter->stapriv; 211 struct sta_info *pbcmc_stainfo = r8712_get_bcmc_stainfo(padapter); 212 213 if (pstapriv->asoc_sta_count == 1) 214 return; 215 spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); 216 for (index = 0; index < NUM_STA; index++) { 217 phead = &(pstapriv->sta_hash[index]); 218 plist = phead->next; 219 while (!end_of_queue_search(phead, plist)) { 220 psta = container_of(plist, 221 struct sta_info, hash_list); 222 plist = plist->next; 223 if (pbcmc_stainfo != psta) 224 r8712_free_stainfo(padapter, psta); 225 } 226 } 227 spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); 228 } 229 230 /* any station allocated can be searched by hash list */ 231 struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) 232 { 233 unsigned long irqL; 234 struct list_head *plist, *phead; 235 struct sta_info *psta = NULL; 236 u32 index; 237 238 if (hwaddr == NULL) 239 return NULL; 240 index = wifi_mac_hash(hwaddr); 241 spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); 242 phead = &(pstapriv->sta_hash[index]); 243 plist = phead->next; 244 while (!end_of_queue_search(phead, plist)) { 245 psta = container_of(plist, struct sta_info, hash_list); 246 if ((!memcmp(psta->hwaddr, hwaddr, ETH_ALEN))) { 247 /* if found the matched address */ 248 break; 249 } 250 psta = NULL; 251 plist = plist->next; 252 } 253 spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); 254 return psta; 255 } 256 257 void r8712_init_bcmc_stainfo(struct _adapter *padapter) 258 { 259 unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 260 struct sta_priv *pstapriv = &padapter->stapriv; 261 262 r8712_alloc_stainfo(pstapriv, bcast_addr); 263 } 264 265 struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter) 266 { 267 struct sta_priv *pstapriv = &padapter->stapriv; 268 u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 269 270 return r8712_get_stainfo(pstapriv, bc_addr); 271 } 272 273 274 u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr) 275 { 276 return true; 277 } 278