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 skb_push(event, MWIFIEX_BSS_START_EVT_FIX_SIZE); 45 46 while ((evt_len >= sizeof(tlv_hdr->header))) { 47 tlv_hdr = (struct mwifiex_ie_types_data *)curr; 48 tlv_len = le16_to_cpu(tlv_hdr->header.len); 49 50 if (evt_len < tlv_len + sizeof(tlv_hdr->header)) 51 break; 52 53 switch (le16_to_cpu(tlv_hdr->header.type)) { 54 case WLAN_EID_HT_CAPABILITY: 55 priv->ap_11n_enabled = true; 56 break; 57 58 case WLAN_EID_VHT_CAPABILITY: 59 priv->ap_11ac_enabled = true; 60 break; 61 62 case WLAN_EID_VENDOR_SPECIFIC: 63 /* Point the regular IEEE IE 2 bytes into the Marvell IE 64 * and setup the IEEE IE type and length byte fields 65 */ 66 wmm_param_ie = (void *)(curr + 2); 67 wmm_param_ie->vend_hdr.len = (u8)tlv_len; 68 wmm_param_ie->vend_hdr.element_id = 69 WLAN_EID_VENDOR_SPECIFIC; 70 mwifiex_dbg(priv->adapter, EVENT, 71 "info: check uap capabilities:\t" 72 "wmm parameter set count: %d\n", 73 wmm_param_ie->qos_info_bitmap & mask); 74 75 mwifiex_wmm_setup_ac_downgrade(priv); 76 priv->wmm_enabled = true; 77 mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie); 78 break; 79 80 default: 81 break; 82 } 83 84 curr += (tlv_len + sizeof(tlv_hdr->header)); 85 evt_len -= (tlv_len + sizeof(tlv_hdr->header)); 86 } 87 88 return 0; 89 } 90 91 /* 92 * This function handles AP interface specific events generated by firmware. 93 * 94 * Event specific routines are called by this function based 95 * upon the generated event cause. 96 * 97 * 98 * Events supported for AP - 99 * - EVENT_UAP_STA_ASSOC 100 * - EVENT_UAP_STA_DEAUTH 101 * - EVENT_UAP_BSS_ACTIVE 102 * - EVENT_UAP_BSS_START 103 * - EVENT_UAP_BSS_IDLE 104 * - EVENT_UAP_MIC_COUNTERMEASURES: 105 */ 106 int mwifiex_process_uap_event(struct mwifiex_private *priv) 107 { 108 struct mwifiex_adapter *adapter = priv->adapter; 109 int len, i; 110 u32 eventcause = adapter->event_cause; 111 struct station_info sinfo; 112 struct mwifiex_assoc_event *event; 113 struct mwifiex_sta_node *node; 114 u8 *deauth_mac; 115 struct host_cmd_ds_11n_batimeout *ba_timeout; 116 u16 ctrl; 117 118 switch (eventcause) { 119 case EVENT_UAP_STA_ASSOC: 120 memset(&sinfo, 0, sizeof(sinfo)); 121 event = (struct mwifiex_assoc_event *) 122 (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER); 123 if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) { 124 len = -1; 125 126 if (ieee80211_is_assoc_req(event->frame_control)) 127 len = 0; 128 else if (ieee80211_is_reassoc_req(event->frame_control)) 129 /* There will be ETH_ALEN bytes of 130 * current_ap_addr before the re-assoc ies. 131 */ 132 len = ETH_ALEN; 133 134 if (len != -1) { 135 sinfo.assoc_req_ies = &event->data[len]; 136 len = (u8 *)sinfo.assoc_req_ies - 137 (u8 *)&event->frame_control; 138 sinfo.assoc_req_ies_len = 139 le16_to_cpu(event->len) - (u16)len; 140 } 141 } 142 cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo, 143 GFP_KERNEL); 144 145 node = mwifiex_add_sta_entry(priv, event->sta_addr); 146 if (!node) { 147 mwifiex_dbg(adapter, ERROR, 148 "could not create station entry!\n"); 149 return -1; 150 } 151 152 if (!priv->ap_11n_enabled) 153 break; 154 155 mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies, 156 sinfo.assoc_req_ies_len, node); 157 158 for (i = 0; i < MAX_NUM_TID; i++) { 159 if (node->is_11n_enabled) 160 node->ampdu_sta[i] = 161 priv->aggr_prio_tbl[i].ampdu_user; 162 else 163 node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED; 164 } 165 memset(node->rx_seq, 0xff, sizeof(node->rx_seq)); 166 break; 167 case EVENT_UAP_STA_DEAUTH: 168 deauth_mac = adapter->event_body + 169 MWIFIEX_UAP_EVENT_EXTRA_HEADER; 170 cfg80211_del_sta(priv->netdev, deauth_mac, GFP_KERNEL); 171 172 if (priv->ap_11n_enabled) { 173 mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac); 174 mwifiex_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac); 175 } 176 mwifiex_wmm_del_peer_ra_list(priv, deauth_mac); 177 mwifiex_del_sta_entry(priv, deauth_mac); 178 break; 179 case EVENT_UAP_BSS_IDLE: 180 priv->media_connected = false; 181 priv->port_open = false; 182 mwifiex_clean_txrx(priv); 183 mwifiex_del_all_sta_list(priv); 184 break; 185 case EVENT_UAP_BSS_ACTIVE: 186 priv->media_connected = true; 187 priv->port_open = true; 188 break; 189 case EVENT_UAP_BSS_START: 190 mwifiex_dbg(adapter, EVENT, 191 "AP EVENT: event id: %#x\n", eventcause); 192 priv->port_open = false; 193 memcpy(priv->netdev->dev_addr, adapter->event_body + 2, 194 ETH_ALEN); 195 if (priv->hist_data) 196 mwifiex_hist_data_reset(priv); 197 mwifiex_check_uap_capabilties(priv, adapter->event_skb); 198 break; 199 case EVENT_UAP_MIC_COUNTERMEASURES: 200 /* For future development */ 201 mwifiex_dbg(adapter, EVENT, 202 "AP EVENT: event id: %#x\n", eventcause); 203 break; 204 case EVENT_AMSDU_AGGR_CTRL: 205 ctrl = le16_to_cpu(*(__le16 *)adapter->event_body); 206 mwifiex_dbg(adapter, EVENT, 207 "event: AMSDU_AGGR_CTRL %d\n", ctrl); 208 209 if (priv->media_connected) { 210 adapter->tx_buf_size = 211 min_t(u16, adapter->curr_tx_buf_size, ctrl); 212 mwifiex_dbg(adapter, EVENT, 213 "event: tx_buf_size %d\n", 214 adapter->tx_buf_size); 215 } 216 break; 217 case EVENT_ADDBA: 218 mwifiex_dbg(adapter, EVENT, "event: ADDBA Request\n"); 219 if (priv->media_connected) 220 mwifiex_send_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP, 221 HostCmd_ACT_GEN_SET, 0, 222 adapter->event_body, false); 223 break; 224 case EVENT_DELBA: 225 mwifiex_dbg(adapter, EVENT, "event: DELBA Request\n"); 226 if (priv->media_connected) 227 mwifiex_11n_delete_ba_stream(priv, adapter->event_body); 228 break; 229 case EVENT_BA_STREAM_TIEMOUT: 230 mwifiex_dbg(adapter, EVENT, "event: BA Stream timeout\n"); 231 if (priv->media_connected) { 232 ba_timeout = (void *)adapter->event_body; 233 mwifiex_11n_ba_stream_timeout(priv, ba_timeout); 234 } 235 break; 236 case EVENT_EXT_SCAN_REPORT: 237 mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n"); 238 if (adapter->ext_scan) 239 return mwifiex_handle_event_ext_scan_report(priv, 240 adapter->event_skb->data); 241 break; 242 case EVENT_TX_STATUS_REPORT: 243 mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); 244 mwifiex_parse_tx_status_event(priv, adapter->event_body); 245 break; 246 case EVENT_PS_SLEEP: 247 mwifiex_dbg(adapter, EVENT, "info: EVENT: SLEEP\n"); 248 249 adapter->ps_state = PS_STATE_PRE_SLEEP; 250 251 mwifiex_check_ps_cond(adapter); 252 break; 253 254 case EVENT_PS_AWAKE: 255 mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n"); 256 if (!adapter->pps_uapsd_mode && 257 priv->media_connected && adapter->sleep_period.period) { 258 adapter->pps_uapsd_mode = true; 259 mwifiex_dbg(adapter, EVENT, 260 "event: PPS/UAPSD mode activated\n"); 261 } 262 adapter->tx_lock_flag = false; 263 if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { 264 if (mwifiex_check_last_packet_indication(priv)) { 265 if (adapter->data_sent || 266 (adapter->if_ops.is_port_ready && 267 !adapter->if_ops.is_port_ready(priv))) { 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 case EVENT_BT_COEX_WLAN_PARA_CHANGE: 296 dev_err(adapter->dev, "EVENT: BT coex wlan param update\n"); 297 mwifiex_bt_coex_wlan_param_update_event(priv, 298 adapter->event_skb); 299 break; 300 case EVENT_TX_DATA_PAUSE: 301 mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); 302 mwifiex_process_tx_pause_event(priv, adapter->event_skb); 303 break; 304 305 case EVENT_MULTI_CHAN_INFO: 306 mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); 307 mwifiex_process_multi_chan_event(priv, adapter->event_skb); 308 break; 309 310 default: 311 mwifiex_dbg(adapter, EVENT, 312 "event: unknown event id: %#x\n", eventcause); 313 break; 314 } 315 316 return 0; 317 } 318 319 /* This function deletes station entry from associated station list. 320 * Also if both AP and STA are 11n enabled, RxReorder tables and TxBA stream 321 * tables created for this station are deleted. 322 */ 323 void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, 324 struct mwifiex_sta_node *node) 325 { 326 if (priv->ap_11n_enabled && node->is_11n_enabled) { 327 mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, node->mac_addr); 328 mwifiex_del_tx_ba_stream_tbl_by_ra(priv, node->mac_addr); 329 } 330 mwifiex_del_sta_entry(priv, node->mac_addr); 331 332 return; 333 } 334