txrx.c (10747B)
1/* 2 * NXP Wireless LAN device driver: generic TX/RX data handling 3 * 4 * Copyright 2011-2020 NXP 5 * 6 * This software file (the "File") is distributed by NXP 7 * 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 "ioctl.h" 22#include "util.h" 23#include "fw.h" 24#include "main.h" 25#include "wmm.h" 26 27/* 28 * This function processes the received buffer. 29 * 30 * Main responsibility of this function is to parse the RxPD to 31 * identify the correct interface this packet is headed for and 32 * forwarding it to the associated handling function, where the 33 * packet will be further processed and sent to kernel/upper layer 34 * if required. 35 */ 36int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, 37 struct sk_buff *skb) 38{ 39 struct mwifiex_private *priv = 40 mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 41 struct rxpd *local_rx_pd; 42 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); 43 int ret; 44 45 local_rx_pd = (struct rxpd *) (skb->data); 46 /* Get the BSS number from rxpd, get corresponding priv */ 47 priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & 48 BSS_NUM_MASK, local_rx_pd->bss_type); 49 if (!priv) 50 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 51 52 if (!priv) { 53 mwifiex_dbg(adapter, ERROR, 54 "data: priv not found. Drop RX packet\n"); 55 dev_kfree_skb_any(skb); 56 return -1; 57 } 58 59 mwifiex_dbg_dump(adapter, DAT_D, "rx pkt:", skb->data, 60 min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN)); 61 62 memset(rx_info, 0, sizeof(*rx_info)); 63 rx_info->bss_num = priv->bss_num; 64 rx_info->bss_type = priv->bss_type; 65 66 if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) 67 ret = mwifiex_process_uap_rx_packet(priv, skb); 68 else 69 ret = mwifiex_process_sta_rx_packet(priv, skb); 70 71 return ret; 72} 73EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); 74 75/* 76 * This function sends a packet to device. 77 * 78 * It processes the packet to add the TxPD, checks condition and 79 * sends the processed packet to firmware for transmission. 80 * 81 * On successful completion, the function calls the completion callback 82 * and logs the time. 83 */ 84int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, 85 struct mwifiex_tx_param *tx_param) 86{ 87 int hroom, ret = -1; 88 struct mwifiex_adapter *adapter = priv->adapter; 89 u8 *head_ptr; 90 struct txpd *local_tx_pd = NULL; 91 struct mwifiex_sta_node *dest_node; 92 struct ethhdr *hdr = (void *)skb->data; 93 94 hroom = adapter->intf_hdr_len; 95 96 if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) { 97 dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest); 98 if (dest_node) { 99 dest_node->stats.tx_bytes += skb->len; 100 dest_node->stats.tx_packets++; 101 } 102 103 head_ptr = mwifiex_process_uap_txpd(priv, skb); 104 } else { 105 head_ptr = mwifiex_process_sta_txpd(priv, skb); 106 } 107 108 if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) { 109 skb_queue_tail(&adapter->tx_data_q, skb); 110 atomic_inc(&adapter->tx_queued); 111 return 0; 112 } 113 114 if (head_ptr) { 115 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) 116 local_tx_pd = (struct txpd *)(head_ptr + hroom); 117 if (adapter->iface_type == MWIFIEX_USB) { 118 ret = adapter->if_ops.host_to_card(adapter, 119 priv->usb_port, 120 skb, tx_param); 121 } else { 122 ret = adapter->if_ops.host_to_card(adapter, 123 MWIFIEX_TYPE_DATA, 124 skb, tx_param); 125 } 126 } 127 mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data, 128 min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN)); 129 130 switch (ret) { 131 case -ENOSR: 132 mwifiex_dbg(adapter, DATA, "data: -ENOSR is returned\n"); 133 break; 134 case -EBUSY: 135 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 136 (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { 137 priv->adapter->tx_lock_flag = false; 138 if (local_tx_pd) 139 local_tx_pd->flags = 0; 140 } 141 mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n"); 142 break; 143 case -1: 144 mwifiex_dbg(adapter, ERROR, 145 "mwifiex_write_data_async failed: 0x%X\n", 146 ret); 147 adapter->dbg.num_tx_host_to_card_failure++; 148 mwifiex_write_data_complete(adapter, skb, 0, ret); 149 break; 150 case -EINPROGRESS: 151 break; 152 case 0: 153 mwifiex_write_data_complete(adapter, skb, 0, ret); 154 break; 155 default: 156 break; 157 } 158 159 return ret; 160} 161 162static int mwifiex_host_to_card(struct mwifiex_adapter *adapter, 163 struct sk_buff *skb, 164 struct mwifiex_tx_param *tx_param) 165{ 166 struct txpd *local_tx_pd = NULL; 167 u8 *head_ptr = skb->data; 168 int ret = 0; 169 struct mwifiex_private *priv; 170 struct mwifiex_txinfo *tx_info; 171 172 tx_info = MWIFIEX_SKB_TXCB(skb); 173 priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num, 174 tx_info->bss_type); 175 if (!priv) { 176 mwifiex_dbg(adapter, ERROR, 177 "data: priv not found. Drop TX packet\n"); 178 adapter->dbg.num_tx_host_to_card_failure++; 179 mwifiex_write_data_complete(adapter, skb, 0, 0); 180 return ret; 181 } 182 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) 183 local_tx_pd = (struct txpd *)(head_ptr + adapter->intf_hdr_len); 184 185 if (adapter->iface_type == MWIFIEX_USB) { 186 ret = adapter->if_ops.host_to_card(adapter, 187 priv->usb_port, 188 skb, tx_param); 189 } else { 190 ret = adapter->if_ops.host_to_card(adapter, 191 MWIFIEX_TYPE_DATA, 192 skb, tx_param); 193 } 194 switch (ret) { 195 case -ENOSR: 196 mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n"); 197 break; 198 case -EBUSY: 199 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 200 (adapter->pps_uapsd_mode) && 201 (adapter->tx_lock_flag)) { 202 priv->adapter->tx_lock_flag = false; 203 if (local_tx_pd) 204 local_tx_pd->flags = 0; 205 } 206 skb_queue_head(&adapter->tx_data_q, skb); 207 if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) 208 atomic_add(tx_info->aggr_num, &adapter->tx_queued); 209 else 210 atomic_inc(&adapter->tx_queued); 211 mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n"); 212 break; 213 case -1: 214 mwifiex_dbg(adapter, ERROR, 215 "mwifiex_write_data_async failed: 0x%X\n", ret); 216 adapter->dbg.num_tx_host_to_card_failure++; 217 mwifiex_write_data_complete(adapter, skb, 0, ret); 218 break; 219 case -EINPROGRESS: 220 break; 221 case 0: 222 mwifiex_write_data_complete(adapter, skb, 0, ret); 223 break; 224 default: 225 break; 226 } 227 return ret; 228} 229 230static int 231mwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter) 232{ 233 struct sk_buff *skb, *skb_next; 234 struct mwifiex_txinfo *tx_info; 235 struct mwifiex_tx_param tx_param; 236 237 skb = skb_dequeue(&adapter->tx_data_q); 238 if (!skb) 239 return -1; 240 241 tx_info = MWIFIEX_SKB_TXCB(skb); 242 if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) 243 atomic_sub(tx_info->aggr_num, &adapter->tx_queued); 244 else 245 atomic_dec(&adapter->tx_queued); 246 247 if (!skb_queue_empty(&adapter->tx_data_q)) 248 skb_next = skb_peek(&adapter->tx_data_q); 249 else 250 skb_next = NULL; 251 tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0); 252 if (!tx_param.next_pkt_len) { 253 if (!mwifiex_wmm_lists_empty(adapter)) 254 tx_param.next_pkt_len = 1; 255 } 256 return mwifiex_host_to_card(adapter, skb, &tx_param); 257} 258 259void 260mwifiex_process_tx_queue(struct mwifiex_adapter *adapter) 261{ 262 do { 263 if (adapter->data_sent || adapter->tx_lock_flag) 264 break; 265 if (mwifiex_dequeue_tx_queue(adapter)) 266 break; 267 } while (!skb_queue_empty(&adapter->tx_data_q)); 268} 269 270/* 271 * Packet send completion callback handler. 272 * 273 * It either frees the buffer directly or forwards it to another 274 * completion callback which checks conditions, updates statistics, 275 * wakes up stalled traffic queue if required, and then frees the buffer. 276 */ 277int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, 278 struct sk_buff *skb, int aggr, int status) 279{ 280 struct mwifiex_private *priv; 281 struct mwifiex_txinfo *tx_info; 282 struct netdev_queue *txq; 283 int index; 284 285 if (!skb) 286 return 0; 287 288 tx_info = MWIFIEX_SKB_TXCB(skb); 289 priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num, 290 tx_info->bss_type); 291 if (!priv) 292 goto done; 293 294 mwifiex_set_trans_start(priv->netdev); 295 296 if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) 297 atomic_dec_return(&adapter->pending_bridged_pkts); 298 299 if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) 300 goto done; 301 302 if (!status) { 303 priv->stats.tx_packets++; 304 priv->stats.tx_bytes += tx_info->pkt_len; 305 if (priv->tx_timeout_cnt) 306 priv->tx_timeout_cnt = 0; 307 } else { 308 priv->stats.tx_errors++; 309 } 310 311 if (aggr) 312 /* For skb_aggr, do not wake up tx queue */ 313 goto done; 314 315 atomic_dec(&adapter->tx_pending); 316 317 index = mwifiex_1d_to_wmm_queue[skb->priority]; 318 if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) { 319 txq = netdev_get_tx_queue(priv->netdev, index); 320 if (netif_tx_queue_stopped(txq)) { 321 netif_tx_wake_queue(txq); 322 mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index); 323 } 324 } 325done: 326 dev_kfree_skb_any(skb); 327 328 return 0; 329} 330EXPORT_SYMBOL_GPL(mwifiex_write_data_complete); 331 332void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, 333 void *event_body) 334{ 335 struct tx_status_event *tx_status = (void *)priv->adapter->event_body; 336 struct sk_buff *ack_skb; 337 struct mwifiex_txinfo *tx_info; 338 339 if (!tx_status->tx_token_id) 340 return; 341 342 spin_lock_bh(&priv->ack_status_lock); 343 ack_skb = idr_remove(&priv->ack_status_frames, tx_status->tx_token_id); 344 spin_unlock_bh(&priv->ack_status_lock); 345 346 if (ack_skb) { 347 tx_info = MWIFIEX_SKB_TXCB(ack_skb); 348 349 if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) { 350 /* consumes ack_skb */ 351 skb_complete_wifi_ack(ack_skb, !tx_status->status); 352 } else { 353 /* Remove broadcast address which was added by driver */ 354 memmove(ack_skb->data + 355 sizeof(struct ieee80211_hdr_3addr) + 356 MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16), 357 ack_skb->data + 358 sizeof(struct ieee80211_hdr_3addr) + 359 MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + 360 ETH_ALEN, ack_skb->len - 361 (sizeof(struct ieee80211_hdr_3addr) + 362 MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + 363 ETH_ALEN)); 364 ack_skb->len = ack_skb->len - ETH_ALEN; 365 /* Remove driver's proprietary header including 2 bytes 366 * of packet length and pass actual management frame buffer 367 * to cfg80211. 368 */ 369 cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, 370 ack_skb->data + 371 MWIFIEX_MGMT_FRAME_HEADER_SIZE + 372 sizeof(u16), ack_skb->len - 373 (MWIFIEX_MGMT_FRAME_HEADER_SIZE 374 + sizeof(u16)), 375 !tx_status->status, GFP_ATOMIC); 376 dev_kfree_skb_any(ack_skb); 377 } 378 } 379}