diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/node.c')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/node.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/node.c b/drivers/net/wireless/ath/ath6kl/node.c new file mode 100644 index 000000000000..131205c610b9 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/node.c | |||
@@ -0,0 +1,234 @@ | |||
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, void *arg) | ||
150 | { | ||
151 | struct bss *ni; | ||
152 | |||
153 | spin_lock_bh(&nt->nt_nodelock); | ||
154 | for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { | ||
155 | ni->ni_refcnt++; | ||
156 | ath6kl_cfg80211_scan_node(arg, ni); | ||
157 | wlan_node_dec_free(ni); | ||
158 | } | ||
159 | spin_unlock_bh(&nt->nt_nodelock); | ||
160 | } | ||
161 | |||
162 | void wlan_node_table_init(struct ath6kl_node_table *nt) | ||
163 | { | ||
164 | ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n", | ||
165 | (unsigned long)nt); | ||
166 | |||
167 | memset(nt, 0, sizeof(struct ath6kl_node_table)); | ||
168 | |||
169 | spin_lock_init(&nt->nt_nodelock); | ||
170 | |||
171 | nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC; | ||
172 | } | ||
173 | |||
174 | void wlan_refresh_inactive_nodes(struct ath6kl *ar) | ||
175 | { | ||
176 | struct ath6kl_node_table *nt = &ar->scan_table; | ||
177 | struct bss *bss; | ||
178 | u32 now; | ||
179 | |||
180 | now = jiffies_to_msecs(jiffies); | ||
181 | bss = nt->nt_node_first; | ||
182 | while (bss != NULL) { | ||
183 | /* refresh all nodes except the current bss */ | ||
184 | if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) { | ||
185 | if (((now - bss->ni_tstamp) > nt->nt_node_age) | ||
186 | || --bss->ni_actcnt == 0) { | ||
187 | wlan_node_reclaim(nt, bss); | ||
188 | } | ||
189 | } | ||
190 | bss = bss->ni_list_next; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | void wlan_node_table_cleanup(struct ath6kl_node_table *nt) | ||
195 | { | ||
196 | wlan_free_allnodes(nt); | ||
197 | } | ||
198 | |||
199 | struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid, | ||
200 | u32 ssid_len, bool is_wpa2, bool match_ssid) | ||
201 | { | ||
202 | struct bss *ni, *found_ni = NULL; | ||
203 | u8 *ie_ssid; | ||
204 | |||
205 | spin_lock_bh(&nt->nt_nodelock); | ||
206 | |||
207 | for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { | ||
208 | |||
209 | ie_ssid = ni->ni_cie.ie_ssid; | ||
210 | |||
211 | if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) && | ||
212 | (memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) { | ||
213 | |||
214 | if (match_ssid || | ||
215 | (is_wpa2 && ni->ni_cie.ie_rsn != NULL) || | ||
216 | (!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) { | ||
217 | ni->ni_refcnt++; | ||
218 | found_ni = ni; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | spin_unlock_bh(&nt->nt_nodelock); | ||
225 | |||
226 | return found_ni; | ||
227 | } | ||
228 | |||
229 | void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni) | ||
230 | { | ||
231 | spin_lock_bh(&nt->nt_nodelock); | ||
232 | wlan_node_dec_free(ni); | ||
233 | spin_unlock_bh(&nt->nt_nodelock); | ||
234 | } | ||