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