533588cb5a1c901a6ff0aae9cfa6e4be7a4d1aa8
[deliverable/linux.git] / drivers / net / wireless / ath / ath6kl / node.c
1 /*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "htc.h"
18 #include "wmi.h"
19 #include "debug.h"
20
21 struct bss *wlan_node_alloc(int wh_size)
22 {
23 struct bss *ni;
24
25 ni = kzalloc(sizeof(struct bss), GFP_ATOMIC);
26
27 if ((ni != NULL) && wh_size) {
28 ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC);
29 if (ni->ni_buf == NULL) {
30 kfree(ni);
31 return NULL;
32 }
33 }
34
35 return ni;
36 }
37
38 void wlan_node_free(struct bss *ni)
39 {
40 kfree(ni->ni_buf);
41 kfree(ni);
42 }
43
44 void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni,
45 const u8 *mac_addr)
46 {
47 int hash;
48
49 memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN);
50 hash = ATH6KL_NODE_HASH(mac_addr);
51 ni->ni_refcnt = 1;
52
53 ni->ni_tstamp = jiffies_to_msecs(jiffies);
54 ni->ni_actcnt = WLAN_NODE_INACT_CNT;
55
56 spin_lock_bh(&nt->nt_nodelock);
57
58 /* insert at the end of the node list */
59 ni->ni_list_next = NULL;
60 ni->ni_list_prev = nt->nt_node_last;
61 if (nt->nt_node_last != NULL)
62 nt->nt_node_last->ni_list_next = ni;
63
64 nt->nt_node_last = ni;
65 if (nt->nt_node_first == NULL)
66 nt->nt_node_first = ni;
67
68 /* insert into the hash list */
69 ni->ni_hash_next = nt->nt_hash[hash];
70 if (ni->ni_hash_next != NULL)
71 nt->nt_hash[hash]->ni_hash_prev = ni;
72
73 ni->ni_hash_prev = NULL;
74 nt->nt_hash[hash] = ni;
75
76 spin_unlock_bh(&nt->nt_nodelock);
77 }
78
79 struct bss *wlan_find_node(struct ath6kl_node_table *nt,
80 const u8 *mac_addr)
81 {
82 struct bss *ni, *found_ni = NULL;
83 int hash;
84
85 spin_lock_bh(&nt->nt_nodelock);
86
87 hash = ATH6KL_NODE_HASH(mac_addr);
88 for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
89 if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) {
90 ni->ni_refcnt++;
91 found_ni = ni;
92 break;
93 }
94 }
95
96 spin_unlock_bh(&nt->nt_nodelock);
97
98 return found_ni;
99 }
100
101 void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni)
102 {
103 int hash;
104
105 spin_lock_bh(&nt->nt_nodelock);
106
107 if (ni->ni_list_prev == NULL)
108 /* fix list head */
109 nt->nt_node_first = ni->ni_list_next;
110 else
111 ni->ni_list_prev->ni_list_next = ni->ni_list_next;
112
113 if (ni->ni_list_next == NULL)
114 /* fix list tail */
115 nt->nt_node_last = ni->ni_list_prev;
116 else
117 ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
118
119 if (ni->ni_hash_prev == NULL) {
120 /* first in list so fix the list head */
121 hash = ATH6KL_NODE_HASH(ni->ni_macaddr);
122 nt->nt_hash[hash] = ni->ni_hash_next;
123 } else {
124 ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
125 }
126
127 if (ni->ni_hash_next != NULL)
128 ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
129
130 wlan_node_free(ni);
131
132 spin_unlock_bh(&nt->nt_nodelock);
133 }
134
135 static void wlan_node_dec_free(struct bss *ni)
136 {
137 if ((ni->ni_refcnt--) == 1)
138 wlan_node_free(ni);
139 }
140
141 void wlan_free_allnodes(struct ath6kl_node_table *nt)
142 {
143 struct bss *ni;
144
145 while ((ni = nt->nt_node_first) != NULL)
146 wlan_node_reclaim(nt, ni);
147 }
148
149 void wlan_iterate_nodes(struct ath6kl_node_table *nt,
150 void (*f) (void *arg, struct bss *), void *arg)
151 {
152 struct bss *ni;
153
154 spin_lock_bh(&nt->nt_nodelock);
155 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
156 ni->ni_refcnt++;
157 (*f) (arg, ni);
158 wlan_node_dec_free(ni);
159 }
160 spin_unlock_bh(&nt->nt_nodelock);
161 }
162
163 void wlan_node_table_init(void *wmi, struct ath6kl_node_table *nt)
164 {
165 ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n",
166 (unsigned long)nt);
167
168 memset(nt, 0, sizeof(struct ath6kl_node_table));
169
170 spin_lock_init(&nt->nt_nodelock);
171
172 nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC;
173 }
174
175 void wlan_refresh_inactive_nodes(struct ath6kl *ar)
176 {
177 struct ath6kl_node_table *nt = &ar->scan_table;
178 struct bss *bss;
179 u8 my_bssid[ETH_ALEN];
180 u32 now;
181
182 ath6kl_wmi_get_current_bssid(ar->wmi, my_bssid);
183
184 now = jiffies_to_msecs(jiffies);
185 bss = nt->nt_node_first;
186 while (bss != NULL) {
187 /* refresh all nodes except the current bss */
188 if (memcmp(my_bssid, bss->ni_macaddr, sizeof(my_bssid)) != 0) {
189 if (((now - bss->ni_tstamp) > nt->nt_node_age)
190 || --bss->ni_actcnt == 0) {
191 wlan_node_reclaim(nt, bss);
192 }
193 }
194 bss = bss->ni_list_next;
195 }
196 }
197
198 void wlan_node_table_cleanup(struct ath6kl_node_table *nt)
199 {
200 wlan_free_allnodes(nt);
201 }
202
203 struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid,
204 u32 ssid_len, bool is_wpa2, bool match_ssid)
205 {
206 struct bss *ni, *found_ni = NULL;
207 u8 *ie_ssid;
208
209 spin_lock_bh(&nt->nt_nodelock);
210
211 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
212
213 ie_ssid = ni->ni_cie.ie_ssid;
214
215 if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
216 (memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) {
217
218 if (match_ssid ||
219 (is_wpa2 && ni->ni_cie.ie_rsn != NULL) ||
220 (!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) {
221 ni->ni_refcnt++;
222 found_ni = ni;
223 break;
224 }
225 }
226 }
227
228 spin_unlock_bh(&nt->nt_nodelock);
229
230 return found_ni;
231 }
232
233 void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni)
234 {
235 spin_lock_bh(&nt->nt_nodelock);
236 wlan_node_dec_free(ni);
237 spin_unlock_bh(&nt->nt_nodelock);
238 }
This page took 0.036146 seconds and 4 git commands to generate.