mwifiex: update AP WMM settings from BSS_START event
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / mwifiex / uap_event.c
1 /*
2  * Marvell Wireless LAN device driver: AP event handling
3  *
4  * Copyright (C) 2012-2014, 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"
22 #include "11n.h"
23
24 #define MWIFIEX_BSS_START_EVT_FIX_SIZE    12
25
26 static int mwifiex_check_uap_capabilties(struct mwifiex_private *priv,
27                                          struct sk_buff *event)
28 {
29         int evt_len;
30         u8 *curr;
31         u16 tlv_len;
32         struct mwifiex_ie_types_data *tlv_hdr;
33         struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
34         int mask = IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK;
35
36         priv->wmm_enabled = false;
37         skb_pull(event, MWIFIEX_BSS_START_EVT_FIX_SIZE);
38         evt_len = event->len;
39         curr = event->data;
40
41         mwifiex_dbg_dump(priv->adapter, EVT_D, "uap capabilties:",
42                          event->data, event->len);
43
44         while ((evt_len >= sizeof(tlv_hdr->header))) {
45                 tlv_hdr = (struct mwifiex_ie_types_data *)curr;
46                 tlv_len = le16_to_cpu(tlv_hdr->header.len);
47
48                 if (evt_len < tlv_len + sizeof(tlv_hdr->header))
49                         break;
50
51                 switch (le16_to_cpu(tlv_hdr->header.type)) {
52                 case WLAN_EID_HT_CAPABILITY:
53                         priv->ap_11n_enabled = true;
54                         break;
55
56                 case WLAN_EID_VHT_CAPABILITY:
57                         priv->ap_11ac_enabled = true;
58                         break;
59
60                 case WLAN_EID_VENDOR_SPECIFIC:
61                         /* Point the regular IEEE IE 2 bytes into the Marvell IE
62                          * and setup the IEEE IE type and length byte fields
63                          */
64                         wmm_param_ie = (void *)(curr + 2);
65                         wmm_param_ie->vend_hdr.len = (u8)tlv_len;
66                         wmm_param_ie->vend_hdr.element_id =
67                                                 WLAN_EID_VENDOR_SPECIFIC;
68                         mwifiex_dbg(priv->adapter, EVENT,
69                                     "info: check uap capabilities:\t"
70                                     "wmm parameter set count: %d\n",
71                                     wmm_param_ie->qos_info_bitmap & mask);
72
73                         mwifiex_wmm_setup_ac_downgrade(priv);
74                         priv->wmm_enabled = true;
75                         mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie);
76                         break;
77
78                 default:
79                         break;
80                 }
81
82                 curr += (tlv_len + sizeof(tlv_hdr->header));
83                 evt_len -= (tlv_len + sizeof(tlv_hdr->header));
84         }
85
86         return 0;
87 }
88
89 /*
90  * This function handles AP interface specific events generated by firmware.
91  *
92  * Event specific routines are called by this function based
93  * upon the generated event cause.
94  *
95  *
96  * Events supported for AP -
97  *      - EVENT_UAP_STA_ASSOC
98  *      - EVENT_UAP_STA_DEAUTH
99  *      - EVENT_UAP_BSS_ACTIVE
100  *      - EVENT_UAP_BSS_START
101  *      - EVENT_UAP_BSS_IDLE
102  *      - EVENT_UAP_MIC_COUNTERMEASURES:
103  */
104 int mwifiex_process_uap_event(struct mwifiex_private *priv)
105 {
106         struct mwifiex_adapter *adapter = priv->adapter;
107         int len, i;
108         u32 eventcause = adapter->event_cause;
109         struct station_info sinfo;
110         struct mwifiex_assoc_event *event;
111         struct mwifiex_sta_node *node;
112         u8 *deauth_mac;
113         struct host_cmd_ds_11n_batimeout *ba_timeout;
114         u16 ctrl;
115
116         switch (eventcause) {
117         case EVENT_UAP_STA_ASSOC:
118                 memset(&sinfo, 0, sizeof(sinfo));
119                 event = (struct mwifiex_assoc_event *)
120                         (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
121                 if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
122                         len = -1;
123
124                         if (ieee80211_is_assoc_req(event->frame_control))
125                                 len = 0;
126                         else if (ieee80211_is_reassoc_req(event->frame_control))
127                                 /* There will be ETH_ALEN bytes of
128                                  * current_ap_addr before the re-assoc ies.
129                                  */
130                                 len = ETH_ALEN;
131
132                         if (len != -1) {
133                                 sinfo.assoc_req_ies = &event->data[len];
134                                 len = (u8 *)sinfo.assoc_req_ies -
135                                       (u8 *)&event->frame_control;
136                                 sinfo.assoc_req_ies_len =
137                                         le16_to_cpu(event->len) - (u16)len;
138                         }
139                 }
140                 cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
141                                  GFP_KERNEL);
142
143                 node = mwifiex_add_sta_entry(priv, event->sta_addr);
144                 if (!node) {
145                         mwifiex_dbg(adapter, ERROR,
146                                     "could not create station entry!\n");
147                         return -1;
148                 }
149
150                 if (!priv->ap_11n_enabled)
151                         break;
152
153                 mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies,
154                                        sinfo.assoc_req_ies_len, node);
155
156                 for (i = 0; i < MAX_NUM_TID; i++) {
157                         if (node->is_11n_enabled)
158                                 node->ampdu_sta[i] =
159                                               priv->aggr_prio_tbl[i].ampdu_user;
160                         else
161                                 node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
162                 }
163                 memset(node->rx_seq, 0xff, sizeof(node->rx_seq));
164                 break;
165         case EVENT_UAP_STA_DEAUTH:
166                 deauth_mac = adapter->event_body +
167                              MWIFIEX_UAP_EVENT_EXTRA_HEADER;
168                 cfg80211_del_sta(priv->netdev, deauth_mac, GFP_KERNEL);
169
170                 if (priv->ap_11n_enabled) {
171                         mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac);
172                         mwifiex_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
173                 }
174                 mwifiex_wmm_del_peer_ra_list(priv, deauth_mac);
175                 mwifiex_del_sta_entry(priv, deauth_mac);
176                 break;
177         case EVENT_UAP_BSS_IDLE:
178                 priv->media_connected = false;
179                 if (netif_carrier_ok(priv->netdev))
180                         netif_carrier_off(priv->netdev);
181                 mwifiex_stop_net_dev_queue(priv->netdev, adapter);
182
183                 mwifiex_clean_txrx(priv);
184                 mwifiex_del_all_sta_list(priv);
185                 break;
186         case EVENT_UAP_BSS_ACTIVE:
187                 priv->media_connected = true;
188                 if (!netif_carrier_ok(priv->netdev))
189                         netif_carrier_on(priv->netdev);
190                 mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
191                 break;
192         case EVENT_UAP_BSS_START:
193                 mwifiex_dbg(adapter, EVENT,
194                             "AP EVENT: event id: %#x\n", eventcause);
195                 memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
196                        ETH_ALEN);
197                 if (priv->hist_data)
198                         mwifiex_hist_data_reset(priv);
199                 mwifiex_check_uap_capabilties(priv, adapter->event_skb);
200                 break;
201         case EVENT_UAP_MIC_COUNTERMEASURES:
202                 /* For future development */
203                 mwifiex_dbg(adapter, EVENT,
204                             "AP EVENT: event id: %#x\n", eventcause);
205                 break;
206         case EVENT_AMSDU_AGGR_CTRL:
207                 ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
208                 mwifiex_dbg(adapter, EVENT,
209                             "event: AMSDU_AGGR_CTRL %d\n", ctrl);
210
211                 if (priv->media_connected) {
212                         adapter->tx_buf_size =
213                                 min_t(u16, adapter->curr_tx_buf_size, ctrl);
214                         mwifiex_dbg(adapter, EVENT,
215                                     "event: tx_buf_size %d\n",
216                                     adapter->tx_buf_size);
217                 }
218                 break;
219         case EVENT_ADDBA:
220                 mwifiex_dbg(adapter, EVENT, "event: ADDBA Request\n");
221                 if (priv->media_connected)
222                         mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP,
223                                          HostCmd_ACT_GEN_SET, 0,
224                                          adapter->event_body, false);
225                 break;
226         case EVENT_DELBA:
227                 mwifiex_dbg(adapter, EVENT, "event: DELBA Request\n");
228                 if (priv->media_connected)
229                         mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
230                 break;
231         case EVENT_BA_STREAM_TIEMOUT:
232                 mwifiex_dbg(adapter, EVENT, "event:  BA Stream timeout\n");
233                 if (priv->media_connected) {
234                         ba_timeout = (void *)adapter->event_body;
235                         mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
236                 }
237                 break;
238         case EVENT_EXT_SCAN_REPORT:
239                 mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n");
240                 if (adapter->ext_scan)
241                         return mwifiex_handle_event_ext_scan_report(priv,
242                                                 adapter->event_skb->data);
243                 break;
244         case EVENT_TX_STATUS_REPORT:
245                 mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n");
246                 mwifiex_parse_tx_status_event(priv, adapter->event_body);
247                 break;
248         case EVENT_PS_SLEEP:
249                 mwifiex_dbg(adapter, EVENT, "info: EVENT: SLEEP\n");
250
251                 adapter->ps_state = PS_STATE_PRE_SLEEP;
252
253                 mwifiex_check_ps_cond(adapter);
254                 break;
255
256         case EVENT_PS_AWAKE:
257                 mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n");
258                 if (!adapter->pps_uapsd_mode &&
259                     priv->media_connected && adapter->sleep_period.period) {
260                                 adapter->pps_uapsd_mode = true;
261                                 mwifiex_dbg(adapter, EVENT,
262                                             "event: PPS/UAPSD mode activated\n");
263                 }
264                 adapter->tx_lock_flag = false;
265                 if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
266                         if (mwifiex_check_last_packet_indication(priv)) {
267                                 if (adapter->data_sent) {
268                                         adapter->ps_state = PS_STATE_AWAKE;
269                                         adapter->pm_wakeup_card_req = false;
270                                         adapter->pm_wakeup_fw_try = false;
271                                         break;
272                                 }
273                                 if (!mwifiex_send_null_packet
274                                         (priv,
275                                          MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
276                                          MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET))
277                                                 adapter->ps_state =
278                                                         PS_STATE_SLEEP;
279                                         return 0;
280                         }
281                 }
282                 adapter->ps_state = PS_STATE_AWAKE;
283                 adapter->pm_wakeup_card_req = false;
284                 adapter->pm_wakeup_fw_try = false;
285                 break;
286
287         case EVENT_CHANNEL_REPORT_RDY:
288                 mwifiex_dbg(adapter, EVENT, "event: Channel Report\n");
289                 mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb);
290                 break;
291         case EVENT_RADAR_DETECTED:
292                 mwifiex_dbg(adapter, EVENT, "event: Radar detected\n");
293                 mwifiex_11h_handle_radar_detected(priv, adapter->event_skb);
294                 break;
295         default:
296                 mwifiex_dbg(adapter, EVENT,
297                             "event: unknown event id: %#x\n", eventcause);
298                 break;
299         }
300
301         return 0;
302 }
303
304 /* This function deletes station entry from associated station list.
305  * Also if both AP and STA are 11n enabled, RxReorder tables and TxBA stream
306  * tables created for this station are deleted.
307  */
308 void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
309                               struct mwifiex_sta_node *node)
310 {
311         if (priv->ap_11n_enabled && node->is_11n_enabled) {
312                 mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, node->mac_addr);
313                 mwifiex_del_tx_ba_stream_tbl_by_ra(priv, node->mac_addr);
314         }
315         mwifiex_del_sta_entry(priv, node->mac_addr);
316
317         return;
318 }