drivers/net/wireless/marvell/mwifiex/uap_txrx.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/marvell/mwifiex/uap_txrx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/marvell/mwifiex/uap_txrx.c
Extension
.c
Size
16337 bytes
Lines
531
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) {
			tx_info = MWIFIEX_SKB_TXCB(skb);
			if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) {
				__skb_unlink(skb, &ra_list->skb_head);
				mwifiex_write_data_complete(adapter, skb, 0,
							    -1);
				if (ra_list->tx_paused)
					priv->wmm.pkts_paused[tid]--;
				else
					atomic_dec(&priv->wmm.tx_pkts_queued);
				pkt_deleted = true;
			}
			if ((atomic_read(&adapter->pending_bridged_pkts) <=
					     MWIFIEX_BRIDGED_PKTS_THR_LOW))
				break;
		}
	}

	return pkt_deleted;
}

/* This function deletes packets from particular RA List. RA list index
 * from which packets are deleted is preserved so that packets from next RA
 * list are deleted upon subsequent call thus maintaining fairness.
 */
static void mwifiex_uap_cleanup_tx_queues(struct mwifiex_private *priv)
{
	struct list_head *ra_list;
	int i;

	spin_lock_bh(&priv->wmm.ra_list_spinlock);

	for (i = 0; i < MAX_NUM_TID; i++, priv->del_list_idx++) {
		if (priv->del_list_idx == MAX_NUM_TID)
			priv->del_list_idx = 0;
		ra_list = &priv->wmm.tid_tbl_ptr[priv->del_list_idx].ra_list;
		if (mwifiex_uap_del_tx_pkts_in_ralist(priv, ra_list, i)) {
			priv->del_list_idx++;
			break;
		}
	}

	spin_unlock_bh(&priv->wmm.ra_list_spinlock);
}


static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
					 struct sk_buff *skb)
{
	struct mwifiex_adapter *adapter = priv->adapter;
	struct uap_rxpd *uap_rx_pd;
	struct rx_packet_hdr *rx_pkt_hdr;
	struct sk_buff *new_skb;
	struct mwifiex_txinfo *tx_info;
	int hdr_chop;
	struct ethhdr *p_ethhdr;
	struct mwifiex_sta_node *src_node;
	int index;

	uap_rx_pd = (struct uap_rxpd *)(skb->data);
	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);

	if ((atomic_read(&adapter->pending_bridged_pkts) >=
					     MWIFIEX_BRIDGED_PKTS_THR_HIGH)) {
		mwifiex_dbg(priv->adapter, ERROR,
			    "Tx: Bridge packet limit reached. Drop packet!\n");
		kfree_skb(skb);
		mwifiex_uap_cleanup_tx_queues(priv);
		return;
	}

	if (sizeof(*rx_pkt_hdr) +
	    le16_to_cpu(uap_rx_pd->rx_pkt_offset) > skb->len) {
		mwifiex_dbg(adapter, ERROR,
			    "wrong rx packet offset: len=%d,rx_pkt_offset=%d\n",
			    skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
		priv->stats.rx_dropped++;
		dev_kfree_skb_any(skb);
		return;
	}

	if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
		     sizeof(bridge_tunnel_header))) ||
	    (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
		     sizeof(rfc1042_header)) &&
	     ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP &&
	     ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX)) {
		/* Replace the 803 header and rfc1042 header (llc/snap) with
		 * an Ethernet II header, keep the src/dst and snap_type
		 * (ethertype).

Annotation

Implementation Notes