lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Tue, 5 Dec 2006 23:26:46 -0500
From:	Michael Wu <flamingice@...rmilk.net>
To:	Ulrich Kunitz <kune@...ne-taler.de>, Daniel Drake <dsd@...too.org>
Cc:	netdev@...r.kernel.org
Subject: [PATCH] zd1211rw-d80211: Use ieee80211_tx_status

zd1211rw-d80211: Use ieee80211_tx_status

This makes zd1211rw-d80211 properly report the TX result of a frame via
ieee80211_tx_status. I'm not sure if we can do much better than this since
the hardware doesn't explicitly report the success/failure of TXed frames 
that require ACKs. We have to guess which ACKs match up with which
frames we're trying to send.

Signed-off-by: Michael Wu <flamingice@...rmilk.net>
---

 drivers/net/wireless/d80211/zd1211rw/zd_chip.h |    3 +
 drivers/net/wireless/d80211/zd1211rw/zd_mac.c  |   96 ++++++++++++++++++++++++
 drivers/net/wireless/d80211/zd1211rw/zd_mac.h  |    2 +
 drivers/net/wireless/d80211/zd1211rw/zd_usb.c  |    8 --
 4 files changed, 99 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_chip.h b/drivers/net/wireless/d80211/zd1211rw/zd_chip.h
index 4eaec47..b9c225d 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_chip.h
@@ -467,8 +467,9 @@
 #define RX_FILTER_BEACON		(1 <<  8)
 #define RX_FILTER_DISASSOC		(1 << 10)
 #define RX_FILTER_AUTH			(1 << 11)
+#define RX_FILTER_ACK			(1 << 29)
 #define AP_RX_FILTER			0x0400feff
-#define STA_RX_FILTER			0x0000ffff
+#define STA_RX_FILTER			0x2000ffff
 
 /* Monitor mode sets filter to 0xfffff */
 
diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_mac.c b/drivers/net/wireless/d80211/zd1211rw/zd_mac.c
index a76fa6a..6ee650f 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_mac.c
@@ -153,6 +153,7 @@ static int zd_mac_stop(struct ieee80211_
 {
 	struct zd_mac *mac = zd_dev_mac(dev);
 	struct zd_chip *chip = &mac->chip;
+	struct sk_buff *skb;
 
 	/*
 	 * The order here deliberately is a little different from the open()
@@ -167,6 +168,13 @@ static int zd_mac_stop(struct ieee80211_
 	zd_chip_switch_radio_off(chip);
 	zd_chip_disable_int(chip);
 
+	while ((skb = skb_dequeue(&mac->tx_queue))) {
+		struct ieee80211_tx_control *control =
+			*(struct ieee80211_tx_control **)skb->cb;
+		kfree(control);
+		kfree_skb(skb);
+	}
+
 	return 0;
 }
 
@@ -312,6 +320,7 @@ static int zd_mac_tx(struct ieee80211_hw
 		     struct ieee80211_tx_control *control)
 {
 	struct zd_mac *mac = zd_dev_mac(dev);
+	struct ieee80211_tx_control *control_copy;
 	int r;
 
 	if (skb_headroom(skb) < dev->extra_tx_headroom &&
@@ -325,11 +334,43 @@ static int zd_mac_tx(struct ieee80211_hw
 	if (r)
 		return r;
 
-	/* FIXME: figure out how to check if the TXed packet was ACKed */
-	kfree_skb(skb);
+	if (control->flags & IEEE80211_TXCTL_NO_ACK) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	control_copy = kmalloc(sizeof(*control_copy), GFP_ATOMIC);
+	if (control_copy)
+		memcpy(control_copy, control, sizeof(*control_copy));
+
+	*(struct ieee80211_tx_control **)skb->cb = control_copy;
+	skb_pull(skb, sizeof(struct zd_ctrlset));
+	skb_queue_tail(&mac->tx_queue, skb);
 	return 0;
 }
 
+void zd_mac_tx_failed(struct ieee80211_hw *dev)
+{
+	struct zd_mac *mac = zd_dev_mac(dev);
+	struct ieee80211_tx_control *control;
+	struct sk_buff *skb;
+
+	skb = skb_dequeue(&mac->tx_queue);
+	if (!skb)
+		return;
+
+	control = *(struct ieee80211_tx_control **)skb->cb;
+	if (control) {
+		struct ieee80211_tx_status status = {{0}};
+		memcpy(&status.control, control, sizeof(status.control));
+		ieee80211_tx_status_irqsafe(dev, skb, &status);
+		kfree(control);
+	} else
+		kfree_skb(skb);
+
+	return;
+}
+
 struct zd_rt_hdr {
 	struct ieee80211_radiotap_header rt_hdr;
 	u8  rt_flags;
@@ -391,6 +432,52 @@ static int fill_rx_stats(struct ieee8021
 	return 0;
 }
 
+static int filter_ack(struct ieee80211_hw *dev, struct ieee80211_hdr *rx_hdr,
+		      struct ieee80211_rx_status *stats)
+{
+	struct zd_mac *mac = zd_dev_mac(dev);
+	u16 fc = le16_to_cpu(rx_hdr->frame_control);
+	struct sk_buff *skb;
+	struct ieee80211_hdr *tx_hdr;
+	struct ieee80211_tx_control *control;
+	struct ieee80211_tx_status status = {{0}};
+
+	if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) !=
+	    (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK))
+		return 0;
+
+	spin_lock(&mac->tx_queue.lock);
+
+	skb = skb_peek(&mac->tx_queue);
+	if (!skb) {
+		spin_unlock(&mac->tx_queue.lock);
+		return 1;
+	}
+
+	tx_hdr = (struct ieee80211_hdr *) skb->data;
+
+	if (!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))
+		skb = __skb_dequeue(&mac->tx_queue);
+	else {
+		spin_unlock(&mac->tx_queue.lock);
+		return 1;
+	}
+
+	spin_unlock(&mac->tx_queue.lock);
+
+	control = *(struct ieee80211_tx_control **)skb->cb;
+	if (control) {
+		memcpy(&status.control, control, sizeof(status.control));
+		status.flags = IEEE80211_TX_STATUS_ACK;
+		status.ack_signal = stats->ssi;
+		ieee80211_tx_status_irqsafe(dev, skb, &status);
+		kfree(control);
+	} else
+		kfree_skb(skb);
+
+	return 1;
+}
+
 int zd_mac_rx(struct ieee80211_hw *dev, const u8 *buffer, unsigned int length)
 {
 	int r;
@@ -411,6 +498,10 @@ int zd_mac_rx(struct ieee80211_hw *dev,
 		  sizeof(struct rx_status);
 	buffer += ZD_PLCP_HEADER_SIZE;
 
+	if (length == (10 /* IEEE80211_1ADDR_LEN */ + FCS_LEN) &&
+	    filter_ack(dev, (struct ieee80211_hdr *)buffer, &stats))
+		return 0;
+
 	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
 	if (!skb)
 		return -ENOMEM;
@@ -523,6 +614,7 @@ struct ieee80211_hw *zd_mac_alloc(struct
 	dev->queues = 1;
 	dev->extra_tx_headroom = sizeof(struct zd_ctrlset);
 
+	skb_queue_head_init(&mac->tx_queue);
 	zd_chip_init(&mac->chip, dev, intf);
 	housekeeping_init(mac);
 
diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_mac.h b/drivers/net/wireless/d80211/zd1211rw/zd_mac.h
index cccf66c..e2ba410 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_mac.h
@@ -135,6 +135,7 @@ struct zd_mac {
 	int mode;
 	int associated;
 	u8 *hwaddr;
+	struct sk_buff_head tx_queue;
 	struct ieee80211_channel channels[14];
 	struct ieee80211_rate rates[12];
 	struct ieee80211_hw_modes modes[2];
@@ -163,6 +164,7 @@ void zd_mac_clear(struct zd_mac *mac);
 int zd_mac_init_hw(struct ieee80211_hw *dev, u8 device_type);
 
 int zd_mac_rx(struct ieee80211_hw *dev, const u8 *buffer, unsigned int length);
+void zd_mac_tx_failed(struct ieee80211_hw *dev);
 
 #ifdef DEBUG
 void zd_dump_rx_status(const struct rx_status *status);
diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_usb.c b/drivers/net/wireless/d80211/zd1211rw/zd_usb.c
index 9112820..bacb019 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_usb.c
@@ -398,12 +398,6 @@ out:
 	spin_unlock(&intr->lock);
 }
 
-static inline void handle_retry_failed_int(struct urb *urb)
-{
-	dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
-}
-
-
 static void int_urb_complete(struct urb *urb)
 {
 	int r;
@@ -439,7 +433,7 @@ static void int_urb_complete(struct urb
 		handle_regs_int(urb);
 		break;
 	case USB_INT_ID_RETRY_FAILED:
-		handle_retry_failed_int(urb);
+		zd_mac_tx_failed(zd_usb_to_dev(urb->context));
 		break;
 	default:
 		dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,

Content of type "application/pgp-signature" skipped

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ