iwlegacy: clean up suspend/resume
[deliverable/linux.git] / drivers / net / wireless / mwifiex / uap_event.c
CommitLineData
3d99d987
AP
1/*
2 * Marvell Wireless LAN device driver: AP event handling
3 *
4 * Copyright (C) 2012, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "main.h"
5a009adf 22#include "11n.h"
3d99d987 23
017a92a1
AP
24/*
25 * This function will return the pointer to station entry in station list
26 * table which matches specified mac address.
27 * This function should be called after acquiring RA list spinlock.
28 * NULL is returned if station entry is not found in associated STA list.
29 */
30struct mwifiex_sta_node *
31mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac)
32{
33 struct mwifiex_sta_node *node;
34
35 if (!mac)
36 return NULL;
37
38 list_for_each_entry(node, &priv->sta_list, list) {
39 if (!memcmp(node->mac_addr, mac, ETH_ALEN))
40 return node;
41 }
42
43 return NULL;
44}
45
46/*
47 * This function will add a sta_node entry to associated station list
48 * table with the given mac address.
49 * If entry exist already, existing entry is returned.
50 * If received mac address is NULL, NULL is returned.
51 */
52static struct mwifiex_sta_node *
53mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac)
54{
55 struct mwifiex_sta_node *node;
56 unsigned long flags;
57
58 if (!mac)
59 return NULL;
60
61 spin_lock_irqsave(&priv->sta_list_spinlock, flags);
62 node = mwifiex_get_sta_entry(priv, mac);
63 if (node)
64 goto done;
65
66 node = kzalloc(sizeof(struct mwifiex_sta_node), GFP_KERNEL);
67 if (!node)
68 goto done;
69
70 memcpy(node->mac_addr, mac, ETH_ALEN);
71 list_add_tail(&node->list, &priv->sta_list);
72
73done:
74 spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
75 return node;
76}
77
78/*
79 * This function will search for HT IE in association request IEs
80 * and set station HT parameters accordingly.
81 */
82static void
83mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
84 int ies_len, struct mwifiex_sta_node *node)
85{
86 const struct ieee80211_ht_cap *ht_cap;
87
88 if (!ies)
89 return;
90
91 ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
92 if (ht_cap) {
93 node->is_11n_enabled = 1;
94 node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
95 IEEE80211_HT_CAP_MAX_AMSDU ?
96 MWIFIEX_TX_DATA_BUF_SIZE_8K :
97 MWIFIEX_TX_DATA_BUF_SIZE_4K;
98 } else {
99 node->is_11n_enabled = 0;
100 }
101
102 return;
103}
104
105/*
106 * This function will delete a station entry from station list
107 */
108static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
109{
110 struct mwifiex_sta_node *node, *tmp;
111 unsigned long flags;
112
113 spin_lock_irqsave(&priv->sta_list_spinlock, flags);
114
115 node = mwifiex_get_sta_entry(priv, mac);
116 if (node) {
117 list_for_each_entry_safe(node, tmp, &priv->sta_list,
118 list) {
119 list_del(&node->list);
120 kfree(node);
121 }
122 }
123
124 spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
125 return;
126}
127
128/*
129 * This function will delete all stations from associated station list.
130 */
131static void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
132{
133 struct mwifiex_sta_node *node, *tmp;
134 unsigned long flags;
135
136 spin_lock_irqsave(&priv->sta_list_spinlock, flags);
137
138 list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
139 list_del(&node->list);
140 kfree(node);
141 }
142
143 INIT_LIST_HEAD(&priv->sta_list);
144 spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
145 return;
146}
147
3d99d987
AP
148/*
149 * This function handles AP interface specific events generated by firmware.
150 *
151 * Event specific routines are called by this function based
152 * upon the generated event cause.
153 *
154 *
155 * Events supported for AP -
156 * - EVENT_UAP_STA_ASSOC
157 * - EVENT_UAP_STA_DEAUTH
158 * - EVENT_UAP_BSS_ACTIVE
159 * - EVENT_UAP_BSS_START
160 * - EVENT_UAP_BSS_IDLE
161 * - EVENT_UAP_MIC_COUNTERMEASURES:
162 */
163int mwifiex_process_uap_event(struct mwifiex_private *priv)
164{
165 struct mwifiex_adapter *adapter = priv->adapter;
017a92a1 166 int len, i;
3d99d987
AP
167 u32 eventcause = adapter->event_cause;
168 struct station_info sinfo;
169 struct mwifiex_assoc_event *event;
017a92a1
AP
170 struct mwifiex_sta_node *node;
171 u8 *deauth_mac;
5a009adf 172 struct host_cmd_ds_11n_batimeout *ba_timeout;
3d99d987
AP
173
174 switch (eventcause) {
175 case EVENT_UAP_STA_ASSOC:
176 memset(&sinfo, 0, sizeof(sinfo));
177 event = (struct mwifiex_assoc_event *)
178 (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
179 if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
180 len = -1;
181
182 if (ieee80211_is_assoc_req(event->frame_control))
183 len = 0;
184 else if (ieee80211_is_reassoc_req(event->frame_control))
185 /* There will be ETH_ALEN bytes of
186 * current_ap_addr before the re-assoc ies.
187 */
188 len = ETH_ALEN;
189
190 if (len != -1) {
191 sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
192 sinfo.assoc_req_ies = &event->data[len];
193 len = (u8 *)sinfo.assoc_req_ies -
194 (u8 *)&event->frame_control;
195 sinfo.assoc_req_ies_len =
196 le16_to_cpu(event->len) - (u16)len;
197 }
198 }
199 cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
200 GFP_KERNEL);
017a92a1
AP
201
202 node = mwifiex_add_sta_entry(priv, event->sta_addr);
203 if (!node) {
204 dev_warn(adapter->dev,
205 "could not create station entry!\n");
206 return -1;
207 }
208
209 if (!priv->ap_11n_enabled)
210 break;
211
212 mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies,
213 sinfo.assoc_req_ies_len, node);
214
215 for (i = 0; i < MAX_NUM_TID; i++) {
216 if (node->is_11n_enabled)
217 node->ampdu_sta[i] =
218 priv->aggr_prio_tbl[i].ampdu_user;
219 else
220 node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
221 }
222 memset(node->rx_seq, 0xff, sizeof(node->rx_seq));
3d99d987
AP
223 break;
224 case EVENT_UAP_STA_DEAUTH:
017a92a1
AP
225 deauth_mac = adapter->event_body +
226 MWIFIEX_UAP_EVENT_EXTRA_HEADER;
227 cfg80211_del_sta(priv->netdev, deauth_mac, GFP_KERNEL);
228
3e238a11
AP
229 if (priv->ap_11n_enabled) {
230 mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac);
231 mwifiex_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
232 }
017a92a1 233 mwifiex_del_sta_entry(priv, deauth_mac);
3d99d987
AP
234 break;
235 case EVENT_UAP_BSS_IDLE:
236 priv->media_connected = false;
3e238a11 237 mwifiex_clean_txrx(priv);
017a92a1 238 mwifiex_del_all_sta_list(priv);
3d99d987
AP
239 break;
240 case EVENT_UAP_BSS_ACTIVE:
241 priv->media_connected = true;
242 break;
243 case EVENT_UAP_BSS_START:
244 dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
245 memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
246 ETH_ALEN);
247 break;
248 case EVENT_UAP_MIC_COUNTERMEASURES:
249 /* For future development */
250 dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
251 break;
d1cf3b95
AP
252 case EVENT_AMSDU_AGGR_CTRL:
253 dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n",
254 *(u16 *)adapter->event_body);
255
256 if (priv->media_connected) {
257 adapter->tx_buf_size =
258 min(adapter->curr_tx_buf_size,
259 le16_to_cpu(*(__le16 *)adapter->event_body));
260
261 dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
262 adapter->tx_buf_size);
263 }
264 break;
5a009adf
AP
265 case EVENT_ADDBA:
266 dev_dbg(adapter->dev, "event: ADDBA Request\n");
267 if (priv->media_connected)
268 mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
269 HostCmd_ACT_GEN_SET, 0,
270 adapter->event_body);
271 break;
272 case EVENT_DELBA:
273 dev_dbg(adapter->dev, "event: DELBA Request\n");
274 if (priv->media_connected)
275 mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
276 break;
277 case EVENT_BA_STREAM_TIEMOUT:
278 dev_dbg(adapter->dev, "event: BA Stream timeout\n");
279 if (priv->media_connected) {
280 ba_timeout = (void *)adapter->event_body;
281 mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
282 }
283 break;
3d99d987
AP
284 default:
285 dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
286 eventcause);
287 break;
288 }
289
290 return 0;
291}
This page took 0.038252 seconds and 5 git commands to generate.