344 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * NXP Wireless LAN device driver: AP event handling4 *5 * Copyright 2011-2020 NXP6 */7 8#include "decl.h"9#include "main.h"10#include "11n.h"11 12#define MWIFIEX_BSS_START_EVT_FIX_SIZE 1213 14static 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 IE52 * and setup the IEEE IE type and length byte fields53 */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 based83 * upon the generated event cause.84 *85 *86 * Events supported for AP -87 * - EVENT_UAP_STA_ASSOC88 * - EVENT_UAP_STA_DEAUTH89 * - EVENT_UAP_BSS_ACTIVE90 * - EVENT_UAP_BSS_START91 * - EVENT_UAP_BSS_IDLE92 * - EVENT_UAP_MIC_COUNTERMEASURES:93 */94int 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 of121 * 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 else157 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_packet268 (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 stream331 * tables created for this station are deleted.332 */333void 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