[WIP] send NULL packets

Holger Schurig hs4233 at mail.mn-solutions.de
Tue Jul 3 04:41:41 EDT 2007


On the CD card, I used simply called hw->host_to_card() to
download the hand crafted TxPD that is supposed to make the card
send a null packet. But this was ill-conceived, because the code
in XXX_host_to_card() in both if_usb.c and if_cs.c assumed that
that it doesn't get called "out of the blue", but from the
main thread (e.g. to re-enable interrupts).

So as a quick (!) hack (!!!!) I fabricate a one-byte skb where
the single data byte in this skb becomes the value of "Flags"
in the TxPD. I then send this skb via dev_queue_xmit() to the
network subsystem and wake the netif queue. In
SendSinglePacket(), which I renamed to libertas_tx_single_pkt()
along the way, I check for this one-byte-skb and act
accordingly.

At least this is race free, even in the case of several buffered
skb's ...

And the data goes out into the card, as can be seen when setting

    echo 0x00210000 >/lib/modules/libertas/parameters/libertas_debug

--- libertas-2.6.orig/drivers/net/wireless/libertas/decl.h
+++ libertas-2.6/drivers/net/wireless/libertas/decl.h
@@ -17,6 +17,7 @@
 
 int libertas_set_mac_packet_filter(wlan_private * priv);
 
+int libertas_send_null_packet(wlan_private *priv, u8 pwr_mgmt);
 void libertas_send_tx_feedback(wlan_private * priv);
 
 int libertas_free_cmd_buffer(wlan_private * priv);
--- libertas-2.6.orig/drivers/net/wireless/libertas/tx.c
+++ libertas-2.6/drivers/net/wireless/libertas/tx.c
@@ -56,13 +56,13 @@
  *  @param skb     A pointer to skb which includes TX packet
  *  @return 	   0 or -1
  */
-static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+static int libertas_tx_single_pkt(wlan_private * priv, struct sk_buff *skb)
 {
 	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	struct txpd localtxpd;
 	struct txpd *plocaltxpd = &localtxpd;
-	u8 *p802x_hdr;
+	u8 *p802x_hdr = NULL;
 	struct tx_radiotap_hdr *pradiotap_hdr;
 	u32 new_rate;
 	u8 *ptr = priv->adapter->tmptxbuf;
@@ -72,9 +72,9 @@
 	if (priv->adapter->surpriseremoved)
 		return -1;
 
-	if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
-		lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
-		       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+	if (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE) {
+		lbs_deb_tx("tx err: skb length > %zd\n",
+		       MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
 		ret = -1;
 		goto done;
 	}
@@ -83,40 +83,48 @@
 
 	plocaltxpd->tx_packet_length = cpu_to_le16(skb->len);
 
-	/* offset of actual data */
-	plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
-
 	/* TxCtrl set by user or default */
 	plocaltxpd->tx_control = cpu_to_le32(adapter->pkttxctrl);
 
-	p802x_hdr = skb->data;
-	if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+	if (likely(skb->len > 1)) {
+		/* offset of actual data */
+		plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
 
-		/* locate radiotap header */
-		pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
+		p802x_hdr = skb->data;
+		if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
 
-		/* set txpd fields from the radiotap header */
-		new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
-		if (new_rate != 0) {
-			/* use new tx_control[4:0] */
-			new_rate |= (adapter->pkttxctrl & ~0x1f);
-			plocaltxpd->tx_control = cpu_to_le32(new_rate);
-		}
+			/* locate radiotap header */
+			pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
 
-		/* skip the radiotap header */
-		p802x_hdr += sizeof(struct tx_radiotap_hdr);
-		plocaltxpd->tx_packet_length =
-			cpu_to_le16(le16_to_cpu(plocaltxpd->tx_packet_length)
+			/* set txpd fields from the radiotap header */
+			new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
+			if (new_rate != 0) {
+				/* use new tx_control[4:0] */
+				new_rate |= (adapter->pkttxctrl & ~0x1f);
+				plocaltxpd->tx_control = cpu_to_le32(new_rate);
+			}
+
+			/* skip the radiotap header */
+			p802x_hdr += sizeof(struct tx_radiotap_hdr);
+			plocaltxpd->tx_packet_length =
+				cpu_to_le16(le16_to_cpu(plocaltxpd->tx_packet_length)
 				    - sizeof(struct tx_radiotap_hdr));
 
+		}
+		/* copy destination address from 802.3 or 802.11 header */
+		if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+			memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+		else
+			memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+	} else
+	if (skb->len == 1) {
+		// Here we send a NULL data packet to tell fake power-
+		// manegement status to the AP
+		plocaltxpd->powermgmt = *skb->data;
+		plocaltxpd->tx_packet_length = 0;
 	}
-	/* copy destination address from 802.3 or 802.11 header */
-	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
-		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
-	else
-		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
 
-	lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+	lbs_deb_hex(LBS_DEB_TX, "Tx Desc", (u8 *) plocaltxpd, sizeof(struct txpd));
 
 	if (IS_MESH_FRAME(skb)) {
 		plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
@@ -124,10 +132,11 @@
 
 	memcpy(ptr, plocaltxpd, sizeof(struct txpd));
 
-	ptr += sizeof(struct txpd);
-
-	lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
-	memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+	if (likely(skb->len > 1)) {
+		ptr += sizeof(struct txpd);
+		lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+		memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+	}
 	ret = priv->hw_host_to_card(priv, MVMS_DAT,
 				    priv->adapter->tmptxbuf,
 				    le16_to_cpu(plocaltxpd->tx_packet_length) +
@@ -138,8 +147,6 @@
 		goto done;
 	}
 
-	lbs_deb_tx("SendSinglePacket succeeds\n");
-
 done:
 	if (!ret) {
 		priv->stats.tx_packets++;
@@ -178,7 +185,7 @@
 	for (i = 0; i < adapter->tx_queue_idx; i++) {
 		struct sk_buff *skb = adapter->tx_queue_ps[i];
 		spin_unlock(&adapter->txqueue_lock);
-		SendSinglePacket(priv, skb);
+		libertas_tx_single_pkt(priv, skb);
 		spin_lock(&adapter->txqueue_lock);
 	}
 	adapter->tx_queue_idx = 0;
@@ -218,7 +225,6 @@
 	int ret = -1;
 
 	lbs_deb_enter(LBS_DEB_TX);
-	lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
 
 	if (priv->dnld_sent) {
 		lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
@@ -234,7 +240,7 @@
 
 	priv->adapter->currenttxskb = skb;
 
-	ret = SendSinglePacket(priv, skb);
+	ret = libertas_tx_single_pkt(priv, skb);
 done:
 	lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
 	return ret;
@@ -285,3 +291,28 @@
 	}
 }
 EXPORT_SYMBOL_GPL(libertas_send_tx_feedback);
+
+
+int libertas_send_null_packet(wlan_private *priv, u8 pwr_mgmt)
+{
+	//wlan_adapter *adapter = priv->adapter;
+	struct sk_buff *skb = NULL;
+	int ret = -1;
+	u8 *data;
+
+	lbs_deb_enter_args(0x00400000, "pwr_mgmt 0x%02x", pwr_mgmt);
+
+	skb = dev_alloc_skb(1);
+	if (!skb)
+		goto out;
+	//skb->protocol = __constant_htons(ETH_P_LOOP);
+	data = skb_put(skb, 1);
+	*data = pwr_mgmt;
+	skb->dev = priv->dev;
+	ret = dev_queue_xmit(skb);
+	netif_wake_queue(priv->dev);
+
+out:
+	lbs_deb_enter_args(LBS_DEB_SCAN, "ret %d", ret);
+	return ret;
+}



More information about the libertas-dev mailing list