OLD | NEW |
(Empty) | |
| 1 //------------------------------------------------------------------------------ |
| 2 // <copyright file="wlan_node.c" company="Atheros"> |
| 3 // Copyright (c) 2004-2008 Atheros Corporation. All rights reserved. |
| 4 // |
| 5 // This program is free software; you can redistribute it and/or modify |
| 6 // it under the terms of the GNU General Public License version 2 as |
| 7 // published by the Free Software Foundation; |
| 8 // |
| 9 // Software distributed under the License is distributed on an "AS |
| 10 // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 11 // implied. See the License for the specific language governing |
| 12 // rights and limitations under the License. |
| 13 // |
| 14 // |
| 15 //------------------------------------------------------------------------------ |
| 16 //============================================================================== |
| 17 // IEEE 802.11 node handling support. |
| 18 // |
| 19 // Author(s): ="Atheros" |
| 20 //============================================================================== |
| 21 #include <a_config.h> |
| 22 #include <athdefs.h> |
| 23 #include <a_types.h> |
| 24 #include <a_osapi.h> |
| 25 #define ATH_MODULE_NAME wlan |
| 26 #include <a_debug.h> |
| 27 #include "htc.h" |
| 28 #include "htc_api.h" |
| 29 #include <wmi.h> |
| 30 #include <ieee80211.h> |
| 31 #include <wlan_api.h> |
| 32 #include <wmi_api.h> |
| 33 #include <ieee80211_node.h> |
| 34 |
| 35 #define ATH_DEBUG_WLAN ATH_DEBUG_MAKE_MODULE_MASK(0) |
| 36 |
| 37 #ifdef DEBUG |
| 38 |
| 39 static ATH_DEBUG_MASK_DESCRIPTION wlan_debug_desc[] = { |
| 40 { ATH_DEBUG_WLAN , "General WLAN Node Tracing"}, |
| 41 }; |
| 42 |
| 43 ATH_DEBUG_INSTANTIATE_MODULE_VAR(wlan, |
| 44 "wlan", |
| 45 "WLAN Node Management", |
| 46 ATH_DEBUG_MASK_DEFAULTS, |
| 47 ATH_DEBUG_DESCRIPTION_COUNT(wlan_debug_desc), |
| 48 wlan_debug_desc); |
| 49 |
| 50 #endif |
| 51 |
| 52 static void wlan_node_timeout(A_ATH_TIMER arg); |
| 53 |
| 54 static bss_t * _ieee80211_find_node (struct ieee80211_node_table *nt, |
| 55 const A_UINT8 *macaddr); |
| 56 |
| 57 bss_t * |
| 58 wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size) |
| 59 { |
| 60 bss_t *ni; |
| 61 |
| 62 ni = A_MALLOC_NOWAIT(sizeof(bss_t)); |
| 63 |
| 64 if (ni != NULL) { |
| 65 if (wh_size) |
| 66 { |
| 67 ni->ni_buf = A_MALLOC_NOWAIT(wh_size); |
| 68 if (ni->ni_buf == NULL) { |
| 69 A_FREE(ni); |
| 70 ni = NULL; |
| 71 return ni; |
| 72 } |
| 73 } |
| 74 } else { |
| 75 return ni; |
| 76 } |
| 77 |
| 78 /* Make sure our lists are clean */ |
| 79 ni->ni_list_next = NULL; |
| 80 ni->ni_list_prev = NULL; |
| 81 ni->ni_hash_next = NULL; |
| 82 ni->ni_hash_prev = NULL; |
| 83 |
| 84 // |
| 85 // ni_scangen never initialized before and during suspend/resume of winmobil
e, |
| 86 // that some junk has been stored in this, due to this scan list didn't prop
erly updated |
| 87 // |
| 88 ni->ni_scangen = 0; |
| 89 |
| 90 #ifdef OS_ROAM_MANAGEMENT |
| 91 ni->ni_si_gen = 0; |
| 92 #endif |
| 93 |
| 94 return ni; |
| 95 } |
| 96 |
| 97 void |
| 98 wlan_node_free(bss_t *ni) |
| 99 { |
| 100 if (ni->ni_buf != NULL) { |
| 101 A_FREE(ni->ni_buf); |
| 102 } |
| 103 A_FREE(ni); |
| 104 } |
| 105 |
| 106 void |
| 107 wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni, |
| 108 const A_UINT8 *macaddr) |
| 109 { |
| 110 int hash; |
| 111 A_UINT32 timeoutValue = 0; |
| 112 |
| 113 A_MEMCPY(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN); |
| 114 hash = IEEE80211_NODE_HASH (macaddr); |
| 115 ieee80211_node_initref (ni); /* mark referenced */ |
| 116 |
| 117 timeoutValue = nt->nt_nodeAge; |
| 118 |
| 119 ni->ni_tstamp = A_GET_MS (timeoutValue); |
| 120 |
| 121 IEEE80211_NODE_LOCK_BH(nt); |
| 122 |
| 123 /* Insert at the end of the node list */ |
| 124 ni->ni_list_next = NULL; |
| 125 ni->ni_list_prev = nt->nt_node_last; |
| 126 if(nt->nt_node_last != NULL) |
| 127 { |
| 128 nt->nt_node_last->ni_list_next = ni; |
| 129 } |
| 130 nt->nt_node_last = ni; |
| 131 if(nt->nt_node_first == NULL) |
| 132 { |
| 133 nt->nt_node_first = ni; |
| 134 } |
| 135 |
| 136 /* Insert into the hash list i.e. the bucket */ |
| 137 if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL) |
| 138 { |
| 139 nt->nt_hash[hash]->ni_hash_prev = ni; |
| 140 } |
| 141 ni->ni_hash_prev = NULL; |
| 142 nt->nt_hash[hash] = ni; |
| 143 |
| 144 if (!nt->isTimerArmed) { |
| 145 A_TIMEOUT_MS(&nt->nt_inact_timer, timeoutValue, 0); |
| 146 nt->isTimerArmed = TRUE; |
| 147 } |
| 148 |
| 149 IEEE80211_NODE_UNLOCK_BH(nt); |
| 150 } |
| 151 |
| 152 static bss_t * |
| 153 _ieee80211_find_node(struct ieee80211_node_table *nt, |
| 154 const A_UINT8 *macaddr) |
| 155 { |
| 156 bss_t *ni; |
| 157 int hash; |
| 158 |
| 159 IEEE80211_NODE_LOCK_ASSERT(nt); |
| 160 |
| 161 hash = IEEE80211_NODE_HASH(macaddr); |
| 162 for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) { |
| 163 if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { |
| 164 ieee80211_node_incref(ni); /* mark referenced */ |
| 165 return ni; |
| 166 } |
| 167 } |
| 168 return NULL; |
| 169 } |
| 170 |
| 171 bss_t * |
| 172 wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr) |
| 173 { |
| 174 bss_t *ni; |
| 175 |
| 176 IEEE80211_NODE_LOCK(nt); |
| 177 ni = _ieee80211_find_node(nt, macaddr); |
| 178 IEEE80211_NODE_UNLOCK(nt); |
| 179 return ni; |
| 180 } |
| 181 |
| 182 /* |
| 183 * Reclaim a node. If this is the last reference count then |
| 184 * do the normal free work. Otherwise remove it from the node |
| 185 * table and mark it gone by clearing the back-reference. |
| 186 */ |
| 187 void |
| 188 wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni) |
| 189 { |
| 190 IEEE80211_NODE_LOCK(nt); |
| 191 |
| 192 if(ni->ni_list_prev == NULL) |
| 193 { |
| 194 /* First in list so fix the list head */ |
| 195 nt->nt_node_first = ni->ni_list_next; |
| 196 } |
| 197 else |
| 198 { |
| 199 ni->ni_list_prev->ni_list_next = ni->ni_list_next; |
| 200 } |
| 201 |
| 202 if(ni->ni_list_next == NULL) |
| 203 { |
| 204 /* Last in list so fix list tail */ |
| 205 nt->nt_node_last = ni->ni_list_prev; |
| 206 } |
| 207 else |
| 208 { |
| 209 ni->ni_list_next->ni_list_prev = ni->ni_list_prev; |
| 210 } |
| 211 |
| 212 if(ni->ni_hash_prev == NULL) |
| 213 { |
| 214 /* First in list so fix the list head */ |
| 215 int hash; |
| 216 hash = IEEE80211_NODE_HASH(ni->ni_macaddr); |
| 217 nt->nt_hash[hash] = ni->ni_hash_next; |
| 218 } |
| 219 else |
| 220 { |
| 221 ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next; |
| 222 } |
| 223 |
| 224 if(ni->ni_hash_next != NULL) |
| 225 { |
| 226 ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev; |
| 227 } |
| 228 wlan_node_free(ni); |
| 229 |
| 230 IEEE80211_NODE_UNLOCK(nt); |
| 231 } |
| 232 |
| 233 static void |
| 234 wlan_node_dec_free(bss_t *ni) |
| 235 { |
| 236 if (ieee80211_node_dectestref(ni)) { |
| 237 wlan_node_free(ni); |
| 238 } |
| 239 } |
| 240 |
| 241 void |
| 242 wlan_free_allnodes(struct ieee80211_node_table *nt) |
| 243 { |
| 244 bss_t *ni; |
| 245 |
| 246 while ((ni = nt->nt_node_first) != NULL) { |
| 247 wlan_node_reclaim(nt, ni); |
| 248 } |
| 249 } |
| 250 |
| 251 void |
| 252 wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f, |
| 253 void *arg) |
| 254 { |
| 255 bss_t *ni; |
| 256 A_UINT32 gen; |
| 257 |
| 258 gen = ++nt->nt_scangen; |
| 259 |
| 260 IEEE80211_NODE_LOCK(nt); |
| 261 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { |
| 262 if (ni->ni_scangen != gen) { |
| 263 ni->ni_scangen = gen; |
| 264 (void) ieee80211_node_incref(ni); |
| 265 (*f)(arg, ni); |
| 266 wlan_node_dec_free(ni); |
| 267 } |
| 268 } |
| 269 IEEE80211_NODE_UNLOCK(nt); |
| 270 } |
| 271 |
| 272 /* |
| 273 * Node table support. |
| 274 */ |
| 275 void |
| 276 wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt) |
| 277 { |
| 278 int i; |
| 279 |
| 280 AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%x\n", (A_UINT32)nt)); |
| 281 IEEE80211_NODE_LOCK_INIT(nt); |
| 282 |
| 283 A_REGISTER_MODULE_DEBUG_INFO(wlan); |
| 284 |
| 285 nt->nt_node_first = nt->nt_node_last = NULL; |
| 286 for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++) |
| 287 { |
| 288 nt->nt_hash[i] = NULL; |
| 289 } |
| 290 |
| 291 A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt); |
| 292 nt->isTimerArmed = FALSE; |
| 293 nt->nt_wmip = wmip; |
| 294 nt->nt_nodeAge = WLAN_NODE_INACT_TIMEOUT_MSEC; |
| 295 |
| 296 // |
| 297 // nt_scangen never initialized before and during suspend/resume of winmobil
e, |
| 298 // that some junk has been stored in this, due to this scan list didn't prop
erly updated |
| 299 // |
| 300 nt->nt_scangen = 0; |
| 301 |
| 302 #ifdef OS_ROAM_MANAGEMENT |
| 303 nt->nt_si_gen = 0; |
| 304 #endif |
| 305 } |
| 306 |
| 307 void |
| 308 wlan_set_nodeage(struct ieee80211_node_table *nt, A_UINT32 nodeAge) |
| 309 { |
| 310 nt->nt_nodeAge = nodeAge; |
| 311 return; |
| 312 } |
| 313 static void |
| 314 wlan_node_timeout (A_ATH_TIMER arg) |
| 315 { |
| 316 struct ieee80211_node_table *nt = (struct ieee80211_node_table *)arg; |
| 317 bss_t *bss, *nextBss; |
| 318 A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = FALSE; |
| 319 A_UINT32 timeoutValue = 0; |
| 320 |
| 321 timeoutValue = nt->nt_nodeAge; |
| 322 |
| 323 wmi_get_current_bssid(nt->nt_wmip, myBssid); |
| 324 |
| 325 bss = nt->nt_node_first; |
| 326 while (bss != NULL) |
| 327 { |
| 328 nextBss = bss->ni_list_next; |
| 329 if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0) |
| 330 { |
| 331 |
| 332 if (bss->ni_tstamp <= A_GET_MS(0)) |
| 333 { |
| 334 /* |
| 335 * free up all but the current bss - if set |
| 336 */ |
| 337 wlan_node_reclaim(nt, bss); |
| 338 } |
| 339 else |
| 340 { |
| 341 /* |
| 342 * Re-arm timer, only when we have a bss other than |
| 343 * current bss AND it is not aged-out. |
| 344 */ |
| 345 reArmTimer = TRUE; |
| 346 } |
| 347 } |
| 348 bss = nextBss; |
| 349 } |
| 350 |
| 351 if (reArmTimer) |
| 352 A_TIMEOUT_MS (&nt->nt_inact_timer, timeoutValue, 0); |
| 353 |
| 354 nt->isTimerArmed = reArmTimer; |
| 355 } |
| 356 |
| 357 void |
| 358 wlan_node_table_cleanup(struct ieee80211_node_table *nt) |
| 359 { |
| 360 A_UNTIMEOUT(&nt->nt_inact_timer); |
| 361 A_DELETE_TIMER(&nt->nt_inact_timer); |
| 362 wlan_free_allnodes(nt); |
| 363 IEEE80211_NODE_LOCK_DESTROY(nt); |
| 364 } |
| 365 |
| 366 bss_t * |
| 367 wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid, |
| 368 A_UINT32 ssidLength, A_BOOL bIsWPA2, A_BOOL bMatchSSID) |
| 369 { |
| 370 bss_t *ni = NULL; |
| 371 A_UCHAR *pIESsid = NULL; |
| 372 |
| 373 IEEE80211_NODE_LOCK (nt); |
| 374 |
| 375 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { |
| 376 pIESsid = ni->ni_cie.ie_ssid; |
| 377 if (pIESsid[1] <= 32) { |
| 378 |
| 379 // Step 1 : Check SSID |
| 380 if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) { |
| 381 |
| 382 // |
| 383 // Step 2.1 : Check MatchSSID is TRUE, if so, return Matched SSI
D |
| 384 // Profile, otherwise check whether WPA2 or WPA |
| 385 // |
| 386 if (TRUE == bMatchSSID) { |
| 387 ieee80211_node_incref (ni); /* mark referenced */ |
| 388 IEEE80211_NODE_UNLOCK (nt); |
| 389 return ni; |
| 390 } |
| 391 |
| 392 // Step 2 : if SSID matches, check WPA or WPA2 |
| 393 if (TRUE == bIsWPA2 && NULL != ni->ni_cie.ie_rsn) { |
| 394 ieee80211_node_incref (ni); /* mark referenced */ |
| 395 IEEE80211_NODE_UNLOCK (nt); |
| 396 return ni; |
| 397 } |
| 398 if (FALSE == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) { |
| 399 ieee80211_node_incref(ni); /* mark referenced */ |
| 400 IEEE80211_NODE_UNLOCK (nt); |
| 401 return ni; |
| 402 } |
| 403 } |
| 404 } |
| 405 } |
| 406 |
| 407 IEEE80211_NODE_UNLOCK (nt); |
| 408 |
| 409 return NULL; |
| 410 } |
| 411 |
| 412 void |
| 413 wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni) |
| 414 { |
| 415 IEEE80211_NODE_LOCK (nt); |
| 416 wlan_node_dec_free (ni); |
| 417 IEEE80211_NODE_UNLOCK (nt); |
| 418 } |
| 419 |
| 420 void |
| 421 wlan_node_remove_core (struct ieee80211_node_table *nt, bss_t *ni) |
| 422 { |
| 423 if(ni->ni_list_prev == NULL) |
| 424 { |
| 425 /* First in list so fix the list head */ |
| 426 nt->nt_node_first = ni->ni_list_next; |
| 427 } |
| 428 else |
| 429 { |
| 430 ni->ni_list_prev->ni_list_next = ni->ni_list_next; |
| 431 } |
| 432 |
| 433 if(ni->ni_list_next == NULL) |
| 434 { |
| 435 /* Last in list so fix list tail */ |
| 436 nt->nt_node_last = ni->ni_list_prev; |
| 437 } |
| 438 else |
| 439 { |
| 440 ni->ni_list_next->ni_list_prev = ni->ni_list_prev; |
| 441 } |
| 442 |
| 443 if(ni->ni_hash_prev == NULL) |
| 444 { |
| 445 /* First in list so fix the list head */ |
| 446 int hash; |
| 447 hash = IEEE80211_NODE_HASH(ni->ni_macaddr); |
| 448 nt->nt_hash[hash] = ni->ni_hash_next; |
| 449 } |
| 450 else |
| 451 { |
| 452 ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next; |
| 453 } |
| 454 |
| 455 if(ni->ni_hash_next != NULL) |
| 456 { |
| 457 ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev; |
| 458 } |
| 459 } |
| 460 |
| 461 bss_t * |
| 462 wlan_node_remove(struct ieee80211_node_table *nt, A_UINT8 *bssid) |
| 463 { |
| 464 bss_t *bss, *nextBss; |
| 465 |
| 466 IEEE80211_NODE_LOCK(nt); |
| 467 |
| 468 bss = nt->nt_node_first; |
| 469 |
| 470 while (bss != NULL) |
| 471 { |
| 472 nextBss = bss->ni_list_next; |
| 473 |
| 474 if (A_MEMCMP(bssid, bss->ni_macaddr, 6) == 0) |
| 475 { |
| 476 wlan_node_remove_core (nt, bss); |
| 477 IEEE80211_NODE_UNLOCK(nt); |
| 478 return bss; |
| 479 } |
| 480 |
| 481 bss = nextBss; |
| 482 } |
| 483 |
| 484 IEEE80211_NODE_UNLOCK(nt); |
| 485 return NULL; |
| 486 } |
OLD | NEW |