linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/14] major mac80211 restructuring/cleanups
@ 2007-06-21 22:16 Johannes Berg
  2007-06-21 22:16 ` [PATCH 02/14] mac80211: move QoS rx handlers into rx.c Johannes Berg
                   ` (13 more replies)
  0 siblings, 14 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

ieee80211.c is just too large to be maintainable. This patch series
splits it up into a few smaller files; it also has a few tiny
buglet-fixes.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 02/14] mac80211: move QoS rx handlers into rx.c
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 03/14] mac80211: rx cleanups (1) Johannes Berg
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

This patch moves the QoS handlers into rx.c making it possible
to compile wme.c only when NET_SCHED is defined.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/Makefile |    2 -
 net/mac80211/rx.c     |   65 ++++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/wme.c    |   73 --------------------------------------------------
 net/mac80211/wme.h    |    9 ++----
 4 files changed, 70 insertions(+), 79 deletions(-)

--- wireless-dev.orig/net/mac80211/rx.c	2007-06-21 19:29:20.218638003 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-06-21 19:29:25.278638003 +0200
@@ -31,6 +31,50 @@
  */
 
 static ieee80211_txrx_result
+ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+{
+	u8 *data = rx->skb->data;
+	int tid;
+	unsigned int is_agg_frame = 0;
+
+	/* does the frame have a qos control field? */
+	if (WLAN_FC_IS_QOS_DATA(rx->fc)) {
+		u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
+
+		/* frame has qos control */
+		rx->u.rx.qos_control = le16_to_cpu(*((__le16*)qc));
+		tid = rx->u.rx.qos_control & QOS_CONTROL_TID_MASK;
+		if (rx->u.rx.qos_control &
+		    IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+			is_agg_frame = 1;
+	} else {
+		if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
+			/* Separate TID for management frames */
+			tid = NUM_RX_DATA_QUEUES - 1;
+		} else {
+			/* no qos control present */
+			tid = 0; /* 802.1d - Best Effort */
+		}
+		rx->u.rx.qos_control = 0;
+	}
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
+	if (rx->sta) {
+		I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
+	}
+#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+
+	rx->u.rx.queue = tid;
+	rx->u.rx.is_agg_frame = is_agg_frame;
+	/* Set skb->priority to 1d tag if highest order bit of TID is not set.
+	 * For now, set skb->priority to 0 for other cases. */
+	rx->skb->priority = (tid > 7) ? 0 : tid;
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
 ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_local *local = rx->local;
@@ -777,6 +821,27 @@ ieee80211_rx_h_ps_poll(struct ieee80211_
 
 
 static ieee80211_txrx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+{
+	u16 fc = rx->fc;
+	u8 *data = rx->skb->data;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
+
+	if (!WLAN_FC_IS_QOS_DATA(fc))
+		return TXRX_CONTINUE;
+
+	/* remove the qos control field, update frame type and meta-data */
+	memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
+	hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
+	/* change frame type to non QOS */
+	rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
+	hdr->frame_control = cpu_to_le16(fc);
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
 ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
 {
 	if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
--- wireless-dev.orig/net/mac80211/wme.c	2007-06-21 19:29:07.088638003 +0200
+++ wireless-dev/net/mac80211/wme.c	2007-06-21 19:29:51.328638003 +0200
@@ -18,78 +18,6 @@
 #include "ieee80211_i.h"
 #include "wme.h"
 
-static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
-{
-	return (fc & 0x8C) == 0x88;
-}
-
-
-ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
-{
-	u8 *data = rx->skb->data;
-	int tid;
-	unsigned int is_agg_frame = 0;
-
-	/* does the frame have a qos control field? */
-	if (WLAN_FC_IS_QOS_DATA(rx->fc)) {
-		u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
-
-		/* frame has qos control */
-		rx->u.rx.qos_control = le16_to_cpu(*((__le16*)qc));
-		tid = rx->u.rx.qos_control & QOS_CONTROL_TID_MASK;
-		if (rx->u.rx.qos_control &
-		    IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
-			is_agg_frame = 1;
-	} else {
-		if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
-			/* Separate TID for management frames */
-			tid = NUM_RX_DATA_QUEUES - 1;
-		} else {
-			/* no qos control present */
-			tid = 0; /* 802.1d - Best Effort */
-		}
-		rx->u.rx.qos_control = 0;
-	}
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-	I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
-	if (rx->sta) {
-		I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
-	}
-#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
-
-	rx->u.rx.queue = tid;
-	rx->u.rx.is_agg_frame = is_agg_frame;
-	/* Set skb->priority to 1d tag if highest order bit of TID is not set.
-	 * For now, set skb->priority to 0 for other cases. */
-	rx->skb->priority = (tid > 7) ? 0 : tid;
-
-	return TXRX_CONTINUE;
-}
-
-
-ieee80211_txrx_result
-ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
-{
-	u16 fc = rx->fc;
-	u8 *data = rx->skb->data;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
-
-	if (!WLAN_FC_IS_QOS_DATA(fc))
-		return TXRX_CONTINUE;
-
-	/* remove the qos control field, update frame type and meta-data */
-	memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
-	hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
-	/* change frame type to non QOS */
-	rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
-	hdr->frame_control = cpu_to_le16(fc);
-
-	return TXRX_CONTINUE;
-}
-
-
-#ifdef CONFIG_NET_SCHED
 /* maximum number of hardware queues we support. */
 #define TC_80211_MAX_QUEUES 8
 
@@ -709,4 +637,3 @@ void ieee80211_wme_unregister(void)
 {
 	unregister_qdisc(&wme_qdisc_ops);
 }
-#endif /* CONFIG_NET_SCHED */
--- wireless-dev.orig/net/mac80211/wme.h	2007-06-21 19:29:07.178638003 +0200
+++ wireless-dev/net/mac80211/wme.h	2007-06-21 19:29:25.288638003 +0200
@@ -24,11 +24,10 @@
 
 #define QOS_CONTROL_TAG1D_MASK 0x07
 
-ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx);
-
-ieee80211_txrx_result
-ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx);
+static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
+{
+	return (fc & 0x8C) == 0x88;
+}
 
 #ifdef CONFIG_NET_SCHED
 void ieee80211_install_qdisc(struct net_device *dev);
--- wireless-dev.orig/net/mac80211/Makefile	2007-06-21 19:29:53.828638003 +0200
+++ wireless-dev/net/mac80211/Makefile	2007-06-21 19:30:12.558638003 +0200
@@ -2,6 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o rc8
 
 mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
 mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
+mac80211-objs-$(CONFIG_NET_SCHED) += wme.o
 
 mac80211-objs := \
 	ieee80211.o \
@@ -16,7 +17,6 @@ mac80211-objs := \
 	regdomain.o \
 	tkip.o \
 	aes_ccm.o \
-	wme.o \
 	ieee80211_cfg.o \
 	rx.o \
 	$(mac80211-objs-y)

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 03/14] mac80211: rx cleanups (1)
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
  2007-06-21 22:16 ` [PATCH 02/14] mac80211: move QoS rx handlers into rx.c Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 04/14] mac80211: split ieee80211_rx_h_check handler Johannes Berg
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

Make some really indented code more readable by outdenting.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/rx.c |  198 +++++++++++++++++++++++++++---------------------------
 1 file changed, 101 insertions(+), 97 deletions(-)

--- wireless-dev.orig/net/mac80211/rx.c	2007-06-21 19:38:16.118638003 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-06-21 20:45:17.428638003 +0200
@@ -1243,21 +1243,24 @@ static inline ieee80211_txrx_result __ie
 
 	for (handler = handlers; *handler != NULL; handler++) {
 		res = (*handler)(rx);
-		if (res != TXRX_CONTINUE) {
-			if (res == TXRX_DROP) {
-				I802_DEBUG_INC(local->rx_handlers_drop);
-				if (sta)
-					sta->rx_dropped++;
-			}
-			if (res == TXRX_QUEUED)
-				I802_DEBUG_INC(local->rx_handlers_queued);
+
+		switch (res) {
+		case TXRX_CONTINUE:
+			continue;
+		case TXRX_DROP:
+			I802_DEBUG_INC(local->rx_handlers_drop);
+			if (sta)
+				sta->rx_dropped++;
+			break;
+		case TXRX_QUEUED:
+			I802_DEBUG_INC(local->rx_handlers_queued);
 			break;
 		}
+		break;
 	}
 
-	if (res == TXRX_DROP) {
+	if (res == TXRX_DROP)
 		dev_kfree_skb(rx->skb);
-	}
 	return res;
 }
 
@@ -1409,6 +1412,9 @@ void __ieee80211_rx(struct ieee80211_hw 
 	u16 type;
 	int multicast;
 	int radiotap_len = 0;
+	struct ieee80211_sub_if_data *prev = NULL;
+	struct sk_buff *skb_new;
+	u8 *bssid;
 
 	if (status->flag & RX_FLAG_RADIOTAP) {
 		radiotap_len = ieee80211_get_radiotap_len(skb->data);
@@ -1456,108 +1462,106 @@ void __ieee80211_rx(struct ieee80211_hw 
 		rx.u.rx.ra_match = 1;
 		ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
 					     sta);
-	} else {
-		struct ieee80211_sub_if_data *prev = NULL;
-		struct sk_buff *skb_new;
-		u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
-
-		read_lock(&local->sub_if_lock);
-		list_for_each_entry(sdata, &local->sub_if_list, list) {
-			rx.u.rx.ra_match = 1;
-			switch (sdata->type) {
-			case IEEE80211_IF_TYPE_STA:
-				if (!bssid)
+		sta_info_put(sta);
+		return;
+	}
+
+	bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
+
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		rx.u.rx.ra_match = 1;
+		switch (sdata->type) {
+		case IEEE80211_IF_TYPE_STA:
+			if (!bssid)
+				continue;
+			if (!ieee80211_bssid_match(bssid,
+						   sdata->u.sta.bssid)) {
+				if (!rx.u.rx.in_scan)
 					continue;
-				if (!ieee80211_bssid_match(bssid,
-							sdata->u.sta.bssid)) {
-					if (!rx.u.rx.in_scan)
-						continue;
-					rx.u.rx.ra_match = 0;
-				} else if (!multicast &&
-					   compare_ether_addr(sdata->dev->dev_addr,
-							      hdr->addr1) != 0) {
-					if (!sdata->promisc)
-						continue;
-					rx.u.rx.ra_match = 0;
-				}
-				break;
-			case IEEE80211_IF_TYPE_IBSS:
-				if (!bssid)
+				rx.u.rx.ra_match = 0;
+			} else if (!multicast &&
+				   compare_ether_addr(sdata->dev->dev_addr,
+						      hdr->addr1) != 0) {
+				if (!sdata->promisc)
 					continue;
-				if (!ieee80211_bssid_match(bssid,
-							sdata->u.sta.bssid)) {
-					if (!rx.u.rx.in_scan)
-						continue;
-					rx.u.rx.ra_match = 0;
-				} else if (!multicast &&
-					   compare_ether_addr(sdata->dev->dev_addr,
-							      hdr->addr1) != 0) {
-					if (!sdata->promisc)
-						continue;
-					rx.u.rx.ra_match = 0;
-				} else if (!sta)
-					sta = rx.sta =
-						ieee80211_ibss_add_sta(sdata->dev,
-								       skb, bssid,
-								       hdr->addr2);
-				break;
-			case IEEE80211_IF_TYPE_AP:
-				if (!bssid) {
-					if (compare_ether_addr(sdata->dev->dev_addr,
-							       hdr->addr1) != 0)
-						continue;
-				} else if (!ieee80211_bssid_match(bssid,
-							sdata->dev->dev_addr)) {
-					if (!rx.u.rx.in_scan)
-						continue;
-					rx.u.rx.ra_match = 0;
-				}
-				if (sdata->dev == local->mdev &&
-				    !rx.u.rx.in_scan)
-					/* do not receive anything via
-					 * master device when not scanning */
+				rx.u.rx.ra_match = 0;
+			}
+			break;
+		case IEEE80211_IF_TYPE_IBSS:
+			if (!bssid)
+				continue;
+			if (!ieee80211_bssid_match(bssid,
+						sdata->u.sta.bssid)) {
+				if (!rx.u.rx.in_scan)
 					continue;
-				break;
-			case IEEE80211_IF_TYPE_WDS:
-				if (bssid ||
-				    (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+				rx.u.rx.ra_match = 0;
+			} else if (!multicast &&
+				   compare_ether_addr(sdata->dev->dev_addr,
+						      hdr->addr1) != 0) {
+				if (!sdata->promisc)
 					continue;
-				if (compare_ether_addr(sdata->u.wds.remote_addr,
-						       hdr->addr2) != 0)
+				rx.u.rx.ra_match = 0;
+			} else if (!sta)
+				sta = rx.sta =
+					ieee80211_ibss_add_sta(sdata->dev,
+							       skb, bssid,
+							       hdr->addr2);
+			break;
+		case IEEE80211_IF_TYPE_AP:
+			if (!bssid) {
+				if (compare_ether_addr(sdata->dev->dev_addr,
+						       hdr->addr1))
 					continue;
-				break;
-			}
-
-			if (prev) {
-				skb_new = skb_copy(skb, GFP_ATOMIC);
-				if (!skb_new) {
-					if (net_ratelimit())
-						printk(KERN_DEBUG "%s: failed to copy "
-						       "multicast frame for %s",
-						       local->mdev->name, prev->dev->name);
+			} else if (!ieee80211_bssid_match(bssid,
+						sdata->dev->dev_addr)) {
+				if (!rx.u.rx.in_scan)
 					continue;
-				}
-				rx.skb = skb_new;
-				rx.dev = prev->dev;
-				rx.sdata = prev;
-				ieee80211_invoke_rx_handlers(local,
-							     local->rx_handlers,
-							     &rx, sta);
+				rx.u.rx.ra_match = 0;
 			}
-			prev = sdata;
+			if (sdata->dev == local->mdev && !rx.u.rx.in_scan)
+				/* do not receive anything via
+				 * master device when not scanning */
+				continue;
+			break;
+		case IEEE80211_IF_TYPE_WDS:
+			if (bssid ||
+			    (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+				continue;
+			if (compare_ether_addr(sdata->u.wds.remote_addr,
+					       hdr->addr2))
+				continue;
+			break;
 		}
+
 		if (prev) {
-			rx.skb = skb;
+			skb_new = skb_copy(skb, GFP_ATOMIC);
+			if (!skb_new) {
+				if (net_ratelimit())
+					printk(KERN_DEBUG "%s: failed to copy "
+					       "multicast frame for %s",
+					       local->mdev->name, prev->dev->name);
+				continue;
+			}
+			rx.skb = skb_new;
 			rx.dev = prev->dev;
 			rx.sdata = prev;
 			ieee80211_invoke_rx_handlers(local, local->rx_handlers,
 						     &rx, sta);
-		} else
-			dev_kfree_skb(skb);
-		read_unlock(&local->sub_if_lock);
+		}
+		prev = sdata;
 	}
+	if (prev) {
+		rx.skb = skb;
+		rx.dev = prev->dev;
+		rx.sdata = prev;
+		ieee80211_invoke_rx_handlers(local, local->rx_handlers,
+					     &rx, sta);
+	} else
+		dev_kfree_skb(skb);
+	read_unlock(&local->sub_if_lock);
 
-  end:
+ end:
 	if (sta)
 		sta_info_put(sta);
 }

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 04/14] mac80211: split ieee80211_rx_h_check handler
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
  2007-06-21 22:16 ` [PATCH 02/14] mac80211: move QoS rx handlers into rx.c Johannes Berg
  2007-06-21 22:16 ` [PATCH 03/14] mac80211: rx cleanups (1) Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 05/14] mac80211: split up __ieee80211_rx Johannes Berg
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

The ieee80211_rx_h_check handler really does two things, it's
a lot easier to understand if it's split into ieee80211_rx_h_check
and ieee80211_rx_h_load_key, and it may be possible in the future
to optimise the key loading to not do it for each interface.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/rx.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

--- wireless-dev.orig/net/mac80211/rx.c	2007-06-21 20:48:50.578638003 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-06-21 20:50:38.678638003 +0200
@@ -248,7 +248,6 @@ static ieee80211_txrx_result
 ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 {
 	struct ieee80211_hdr *hdr;
-	int always_sta_key;
 	hdr = (struct ieee80211_hdr *) rx->skb->data;
 
 	/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
@@ -316,6 +315,16 @@ ieee80211_rx_h_check(struct ieee80211_tx
 		return TXRX_QUEUED;
 	}
 
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+	int always_sta_key;
+
 	if (rx->sdata->type == IEEE80211_IF_TYPE_STA)
 		always_sta_key = 0;
 	else
@@ -1373,6 +1382,7 @@ ieee80211_rx_handler ieee80211_rx_handle
 	ieee80211_rx_h_monitor,
 	ieee80211_rx_h_passive_scan,
 	ieee80211_rx_h_check,
+	ieee80211_rx_h_load_key,
 	ieee80211_rx_h_sta_process,
 	ieee80211_rx_h_ccmp_decrypt,
 	ieee80211_rx_h_tkip_decrypt,

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 05/14] mac80211: split up __ieee80211_rx
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (2 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 04/14] mac80211: split ieee80211_rx_h_check handler Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 06/14] mac80211: fix bug for per-sta stats Johannes Berg
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

The really indented part that does the huge switch on the interface
type is a nuisance. Put it into an own function 'prepare_for_handlers'.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/rx.c |  157 ++++++++++++++++++++++++++++--------------------------
 1 file changed, 83 insertions(+), 74 deletions(-)

--- wireless-dev.orig/net/mac80211/rx.c	2007-06-21 21:27:42.378638003 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-06-21 21:29:55.848638003 +0200
@@ -1407,6 +1407,73 @@ ieee80211_rx_handler ieee80211_rx_handle
 
 /* main receive path */
 
+static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
+				u8 *bssid, struct ieee80211_txrx_data *rx,
+				struct ieee80211_hdr *hdr)
+{
+	int multicast = is_multicast_ether_addr(hdr->addr1);
+
+	switch (sdata->type) {
+	case IEEE80211_IF_TYPE_STA:
+		if (!bssid)
+			return 0;
+		if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+			if (!rx->u.rx.in_scan)
+				return 0;
+			rx->u.rx.ra_match = 0;
+		} else if (!multicast &&
+			   compare_ether_addr(sdata->dev->dev_addr,
+					      hdr->addr1) != 0) {
+			if (!sdata->promisc)
+				return 0;
+			rx->u.rx.ra_match = 0;
+		}
+		break;
+	case IEEE80211_IF_TYPE_IBSS:
+		if (!bssid)
+			return 0;
+		if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+			if (!rx->u.rx.in_scan)
+				return 0;
+			rx->u.rx.ra_match = 0;
+		} else if (!multicast &&
+			   compare_ether_addr(sdata->dev->dev_addr,
+					      hdr->addr1) != 0) {
+			if (!sdata->promisc)
+				return 0;
+			rx->u.rx.ra_match = 0;
+		} else if (!rx->sta)
+			rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
+							 bssid, hdr->addr2);
+		break;
+	case IEEE80211_IF_TYPE_AP:
+		if (!bssid) {
+			if (compare_ether_addr(sdata->dev->dev_addr,
+					       hdr->addr1))
+				return 0;
+		} else if (!ieee80211_bssid_match(bssid,
+					sdata->dev->dev_addr)) {
+			if (!rx->u.rx.in_scan)
+				return 0;
+			rx->u.rx.ra_match = 0;
+		}
+		if (sdata->dev == sdata->local->mdev && !rx->u.rx.in_scan)
+			/* do not receive anything via
+			 * master device when not scanning */
+			return 0;
+		break;
+	case IEEE80211_IF_TYPE_WDS:
+		if (bssid ||
+		    (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+			return 0;
+		if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
+			return 0;
+		break;
+	}
+
+	return 1;
+}
+
 /*
  * This is the receive path handler. It is called by a low level driver when an
  * 802.11 MPDU is received from the hardware.
@@ -1420,8 +1487,7 @@ void __ieee80211_rx(struct ieee80211_hw 
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_txrx_data rx;
 	u16 type;
-	int multicast;
-	int radiotap_len = 0;
+	int radiotap_len = 0, prepres;
 	struct ieee80211_sub_if_data *prev = NULL;
 	struct sk_buff *skb_new;
 	u8 *bssid;
@@ -1441,18 +1507,16 @@ void __ieee80211_rx(struct ieee80211_hw 
 	type = rx.fc & IEEE80211_FCTL_FTYPE;
 	if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
 		local->dot11ReceivedFragmentCount++;
-	multicast = is_multicast_ether_addr(hdr->addr1);
 
-	if (skb->len >= 16)
+	if (skb->len >= 16) {
 		sta = rx.sta = sta_info_get(local, hdr->addr2);
-	else
+		if (sta) {
+			rx.dev = rx.sta->dev;
+			rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+		}
+	} else
 		sta = rx.sta = NULL;
 
-	if (sta) {
-		rx.dev = sta->dev;
-		rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
-	}
-
 	if ((status->flag & RX_FLAG_MMIC_ERROR)) {
 		ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
 		goto end;
@@ -1468,10 +1532,10 @@ void __ieee80211_rx(struct ieee80211_hw 
 
 	skb_push(skb, radiotap_len);
 	if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
-	    !local->iff_promiscs && !multicast) {
+	    !local->iff_promiscs && !is_multicast_ether_addr(hdr->addr1)) {
 		rx.u.rx.ra_match = 1;
 		ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
-					     sta);
+					     rx.sta);
 		sta_info_put(sta);
 		return;
 	}
@@ -1481,68 +1545,13 @@ void __ieee80211_rx(struct ieee80211_hw 
 	read_lock(&local->sub_if_lock);
 	list_for_each_entry(sdata, &local->sub_if_list, list) {
 		rx.u.rx.ra_match = 1;
-		switch (sdata->type) {
-		case IEEE80211_IF_TYPE_STA:
-			if (!bssid)
-				continue;
-			if (!ieee80211_bssid_match(bssid,
-						   sdata->u.sta.bssid)) {
-				if (!rx.u.rx.in_scan)
-					continue;
-				rx.u.rx.ra_match = 0;
-			} else if (!multicast &&
-				   compare_ether_addr(sdata->dev->dev_addr,
-						      hdr->addr1) != 0) {
-				if (!sdata->promisc)
-					continue;
-				rx.u.rx.ra_match = 0;
-			}
-			break;
-		case IEEE80211_IF_TYPE_IBSS:
-			if (!bssid)
-				continue;
-			if (!ieee80211_bssid_match(bssid,
-						sdata->u.sta.bssid)) {
-				if (!rx.u.rx.in_scan)
-					continue;
-				rx.u.rx.ra_match = 0;
-			} else if (!multicast &&
-				   compare_ether_addr(sdata->dev->dev_addr,
-						      hdr->addr1) != 0) {
-				if (!sdata->promisc)
-					continue;
-				rx.u.rx.ra_match = 0;
-			} else if (!sta)
-				sta = rx.sta =
-					ieee80211_ibss_add_sta(sdata->dev,
-							       skb, bssid,
-							       hdr->addr2);
-			break;
-		case IEEE80211_IF_TYPE_AP:
-			if (!bssid) {
-				if (compare_ether_addr(sdata->dev->dev_addr,
-						       hdr->addr1))
-					continue;
-			} else if (!ieee80211_bssid_match(bssid,
-						sdata->dev->dev_addr)) {
-				if (!rx.u.rx.in_scan)
-					continue;
-				rx.u.rx.ra_match = 0;
-			}
-			if (sdata->dev == local->mdev && !rx.u.rx.in_scan)
-				/* do not receive anything via
-				 * master device when not scanning */
-				continue;
-			break;
-		case IEEE80211_IF_TYPE_WDS:
-			if (bssid ||
-			    (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-				continue;
-			if (compare_ether_addr(sdata->u.wds.remote_addr,
-					       hdr->addr2))
-				continue;
-			break;
-		}
+
+		prepres = prepare_for_handlers(sdata, bssid, &rx, hdr);
+		/* prepare_for_handlers can change sta */
+		sta = rx.sta;
+
+		if (!prepres)
+			continue;
 
 		if (prev) {
 			skb_new = skb_copy(skb, GFP_ATOMIC);

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 06/14] mac80211: fix bug for per-sta stats
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (3 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 05/14] mac80211: split up __ieee80211_rx Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 07/14] mac80211: rx cleanups (2) Johannes Berg
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

pre_rx handlers can't really touch sta since for IBSS it might not be
assigned yet, it can create sta info structs on-the-fly.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/rx.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

--- wireless-dev.orig/net/mac80211/rx.c	2007-06-21 21:40:59.028638003 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-06-21 21:43:01.838638003 +0200
@@ -28,6 +28,8 @@
 /* pre-rx handlers
  *
  * these don't have dev/sdata fields in the rx data
+ * The sta value should also not be used because it may
+ * be NULL even though a STA (in IBSS mode) will be added.
  */
 
 static ieee80211_txrx_result
@@ -57,12 +59,11 @@ ieee80211_rx_h_parse_qos(struct ieee8021
 		}
 		rx->u.rx.qos_control = 0;
 	}
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+
 	I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
-	if (rx->sta) {
+	/* only a debug counter, sta might not be assigned properly yet */
+	if (rx->sta)
 		I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
-	}
-#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
 
 	rx->u.rx.queue = tid;
 	rx->u.rx.is_agg_frame = is_agg_frame;
@@ -119,8 +120,6 @@ ieee80211_rx_h_load_stats(struct ieee802
 	/* Divide channel_use by 8 to avoid wrapping around the counter */
 	load >>= CHAN_UTIL_SHIFT;
 	local->channel_use_raw += load;
-	if (rx->sta)
-		rx->sta->channel_use_raw += load;
 	rx->u.rx.load = load;
 
 	return TXRX_CONTINUE;
@@ -140,6 +139,8 @@ ieee80211_rx_handler ieee80211_rx_pre_ha
 static ieee80211_txrx_result
 ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
 {
+	if (rx->sta)
+		rx->sta->channel_use_raw += rx->u.rx.load;
 	rx->sdata->channel_use_raw += rx->u.rx.load;
 	return TXRX_CONTINUE;
 }

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 07/14] mac80211: rx cleanups (2)
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (4 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 06/14] mac80211: fix bug for per-sta stats Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 09/14] mac80211: remove some unnecessary includes Johannes Berg
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

Some more outdenting to make the code more readable.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/rx.c |   42 ++++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 14 deletions(-)

--- wireless-dev.orig/net/mac80211/rx.c	2007-06-21 22:04:10.758638003 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-06-21 22:07:01.148638003 +0200
@@ -1554,21 +1554,35 @@ void __ieee80211_rx(struct ieee80211_hw 
 		if (!prepres)
 			continue;
 
-		if (prev) {
-			skb_new = skb_copy(skb, GFP_ATOMIC);
-			if (!skb_new) {
-				if (net_ratelimit())
-					printk(KERN_DEBUG "%s: failed to copy "
-					       "multicast frame for %s",
-					       local->mdev->name, prev->dev->name);
-				continue;
-			}
-			rx.skb = skb_new;
-			rx.dev = prev->dev;
-			rx.sdata = prev;
-			ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-						     &rx, sta);
+		/*
+		 * frame is destined for this interface, but if it's not
+		 * also for the previous one we handle that after the
+		 * loop to avoid copying the SKB once too much
+		 */
+
+		if (!prev) {
+			prev = sdata;
+			continue;
+		}
+
+		/*
+		 * frame was destined for the previous interface
+		 * so invoke RX handlers for it
+		 */
+
+		skb_new = skb_copy(skb, GFP_ATOMIC);
+		if (!skb_new) {
+			if (net_ratelimit())
+				printk(KERN_DEBUG "%s: failed to copy "
+				       "multicast frame for %s",
+				       local->mdev->name, prev->dev->name);
+			continue;
 		}
+		rx.skb = skb_new;
+		rx.dev = prev->dev;
+		rx.sdata = prev;
+		ieee80211_invoke_rx_handlers(local, local->rx_handlers,
+					     &rx, sta);
 		prev = sdata;
 	}
 	if (prev) {

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 09/14] mac80211: remove some unnecessary includes
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (5 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 07/14] mac80211: rx cleanups (2) Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 10/14] mac80211: split out some key functions from ieee80211.c Johannes Berg
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/ieee80211.c |    4 ----
 1 file changed, 4 deletions(-)

--- wireless-dev.orig/net/mac80211/ieee80211.c	2007-06-21 23:21:43.858638003 +0200
+++ wireless-dev/net/mac80211/ieee80211.c	2007-06-21 23:24:21.928638003 +0200
@@ -20,8 +20,6 @@
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/rtnetlink.h>
-#include <net/iw_handler.h>
-#include <linux/compiler.h>
 #include <linux/bitmap.h>
 #include <net/cfg80211.h>
 
@@ -29,8 +27,6 @@
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
 #include "wep.h"
-#include "wpa.h"
-#include "tkip.h"
 #include "wme.h"
 #include "aes_ccm.h"
 #include "ieee80211_led.h"

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 10/14] mac80211: split out some key functions from  ieee80211.c
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (6 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 09/14] mac80211: remove some unnecessary includes Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 11/14] mac80211: regdomain.c needs to include ieee80211_i.h Johannes Berg
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

into a new file key.c which doesn't have much code right now but
it makes ieee80211.c easier to read.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/Makefile      |    1 
 net/mac80211/ieee80211.c   |   56 ------------------------------------
 net/mac80211/ieee80211_i.h |   14 +++++----
 net/mac80211/key.c         |   69 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 62 deletions(-)

--- wireless-dev.orig/net/mac80211/ieee80211.c	2007-06-21 23:27:02.648638003 +0200
+++ wireless-dev/net/mac80211/ieee80211.c	2007-06-21 23:30:12.518638003 +0200
@@ -33,7 +33,6 @@
 #include "ieee80211_cfg.h"
 #include "debugfs.h"
 #include "debugfs_netdev.h"
-#include "debugfs_key.h"
 
 /* privid for wiphys to determine whether they belong to us or not */
 void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -63,61 +62,6 @@ struct ieee80211_tx_status_rtap_hdr {
 } __attribute__ ((packed));
 
 
-struct ieee80211_key_conf *
-ieee80211_key_data2conf(struct ieee80211_local *local,
-			const struct ieee80211_key *data)
-{
-	struct ieee80211_key_conf *conf;
-
-	conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC);
-	if (!conf)
-		return NULL;
-
-	conf->hw_key_idx = data->hw_key_idx;
-	conf->alg = data->alg;
-	conf->keylen = data->keylen;
-	conf->flags = 0;
-	if (data->force_sw_encrypt)
-		conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
-	conf->keyidx = data->keyidx;
-	if (data->default_tx_key)
-		conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY;
-	if (local->default_wep_only)
-		conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY;
-	memcpy(conf->key, data->key, data->keylen);
-
-	return conf;
-}
-
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
-					  int idx, size_t key_len, gfp_t flags)
-{
-	struct ieee80211_key *key;
-
-	key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags);
-	if (!key)
-		return NULL;
-	kref_init(&key->kref);
-	return key;
-}
-
-static void ieee80211_key_release(struct kref *kref)
-{
-	struct ieee80211_key *key;
-
-	key = container_of(kref, struct ieee80211_key, kref);
-	if (key->alg == ALG_CCMP)
-		ieee80211_aes_key_free(key->u.ccmp.tfm);
-	ieee80211_debugfs_key_remove(key);
-	kfree(key);
-}
-
-void ieee80211_key_free(struct ieee80211_key *key)
-{
-	if (key)
-		kref_put(&key->kref, ieee80211_key_release);
-}
-
 static int rate_list_match(const int *rate_list, int rate)
 {
 	int i;
--- wireless-dev.orig/net/mac80211/ieee80211_i.h	2007-06-21 23:26:37.288638003 +0200
+++ wireless-dev/net/mac80211/ieee80211_i.h	2007-06-21 23:29:27.118638003 +0200
@@ -795,12 +795,6 @@ static inline int ieee80211_bssid_match(
 int ieee80211_hw_config(struct ieee80211_local *local);
 int ieee80211_if_config(struct net_device *dev);
 int ieee80211_if_config_beacon(struct net_device *dev);
-struct ieee80211_key_conf *
-ieee80211_key_data2conf(struct ieee80211_local *local,
-			const struct ieee80211_key *data);
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
-					  int idx, size_t key_len, gfp_t flags);
-void ieee80211_key_free(struct ieee80211_key *key);
 void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
 		       struct ieee80211_rx_status *status, u32 msg_type);
 void ieee80211_prepare_rates(struct ieee80211_local *local,
@@ -936,6 +930,14 @@ int ieee80211_monitor_start_xmit(struct 
 int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
+/* key handling */
+struct ieee80211_key_conf *
+ieee80211_key_data2conf(struct ieee80211_local *local,
+			const struct ieee80211_key *data);
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+					  int idx, size_t key_len, gfp_t flags);
+void ieee80211_key_free(struct ieee80211_key *key);
+
 /* for wiphy privid */
 extern void *mac80211_wiphy_privid;
 
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/mac80211/key.c	2007-06-21 23:31:03.308638003 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "debugfs_key.h"
+#include "aes_ccm.h"
+
+struct ieee80211_key_conf *
+ieee80211_key_data2conf(struct ieee80211_local *local,
+			const struct ieee80211_key *data)
+{
+	struct ieee80211_key_conf *conf;
+
+	conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC);
+	if (!conf)
+		return NULL;
+
+	conf->hw_key_idx = data->hw_key_idx;
+	conf->alg = data->alg;
+	conf->keylen = data->keylen;
+	conf->flags = 0;
+	if (data->force_sw_encrypt)
+		conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
+	conf->keyidx = data->keyidx;
+	if (data->default_tx_key)
+		conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY;
+	if (local->default_wep_only)
+		conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY;
+	memcpy(conf->key, data->key, data->keylen);
+
+	return conf;
+}
+
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+					  int idx, size_t key_len, gfp_t flags)
+{
+	struct ieee80211_key *key;
+
+	key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags);
+	if (!key)
+		return NULL;
+	kref_init(&key->kref);
+	return key;
+}
+
+static void ieee80211_key_release(struct kref *kref)
+{
+	struct ieee80211_key *key;
+
+	key = container_of(kref, struct ieee80211_key, kref);
+	if (key->alg == ALG_CCMP)
+		ieee80211_aes_key_free(key->u.ccmp.tfm);
+	ieee80211_debugfs_key_remove(key);
+	kfree(key);
+}
+
+void ieee80211_key_free(struct ieee80211_key *key)
+{
+	if (key)
+		kref_put(&key->kref, ieee80211_key_release);
+}
--- wireless-dev.orig/net/mac80211/Makefile	2007-06-21 23:27:51.778638003 +0200
+++ wireless-dev/net/mac80211/Makefile	2007-06-21 23:27:55.088638003 +0200
@@ -20,4 +20,5 @@ mac80211-objs := \
 	ieee80211_cfg.o \
 	rx.o \
 	tx.o \
+	key.o \
 	$(mac80211-objs-y)

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 11/14] mac80211: regdomain.c needs to include ieee80211_i.h
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (7 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 10/14] mac80211: split out some key functions from ieee80211.c Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 12/14] mac80211: move some rate control functions out of ieee80211.c Johannes Berg
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/regdomain.c |    1 +
 1 file changed, 1 insertion(+)

--- wireless-dev.orig/net/mac80211/regdomain.c	2007-06-21 23:36:58.758638003 +0200
+++ wireless-dev/net/mac80211/regdomain.c	2007-06-21 23:37:19.988638003 +0200
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <net/mac80211.h>
+#include "ieee80211_i.h"
 
 static int ieee80211_regdom = 0x10; /* FCC */
 module_param(ieee80211_regdom, int, 0444);

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 12/14] mac80211: move some rate control functions out of  ieee80211.c
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (8 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 11/14] mac80211: regdomain.c needs to include ieee80211_i.h Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 13/14] mac80211: reorder interface related functions Johannes Berg
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

I think these can go with rate control just as well and it makes
ieee80211.c more readable.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/ieee80211.c      |   41 -----------------------------------------
 net/mac80211/ieee80211_i.h    |    2 --
 net/mac80211/ieee80211_rate.c |   42 ++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/ieee80211_rate.h |    6 ++++++
 4 files changed, 48 insertions(+), 43 deletions(-)

--- wireless-dev.orig/net/mac80211/ieee80211.c	2007-06-21 23:41:18.698638003 +0200
+++ wireless-dev/net/mac80211/ieee80211.c	2007-06-21 23:41:34.598638003 +0200
@@ -1546,47 +1546,6 @@ void ieee80211_if_mgmt_setup(struct net_
 	dev->destructor = ieee80211_if_free;
 }
 
-int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
-				 const char *name)
-{
-	struct rate_control_ref *ref, *old;
-
-	ASSERT_RTNL();
-	if (local->open_count || netif_running(local->mdev) ||
-	    (local->apdev && netif_running(local->apdev)))
-		return -EBUSY;
-
-	ref = rate_control_alloc(name, local);
-	if (!ref) {
-		printk(KERN_WARNING "%s: Failed to select rate control "
-		       "algorithm\n", local->mdev->name);
-		return -ENOENT;
-	}
-
-	old = local->rate_ctrl;
-	local->rate_ctrl = ref;
-	if (old) {
-		rate_control_put(old);
-		sta_info_flush(local, NULL);
-	}
-
-	printk(KERN_DEBUG "%s: Selected rate control "
-	       "algorithm '%s'\n", local->mdev->name,
-	       ref->ops->name);
-
-
-	return 0;
-}
-
-static void rate_control_deinitialize(struct ieee80211_local *local)
-{
-	struct rate_control_ref *ref;
-
-	ref = local->rate_ctrl;
-	local->rate_ctrl = NULL;
-	rate_control_put(ref);
-}
-
 
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 					const struct ieee80211_ops *ops)
--- wireless-dev.orig/net/mac80211/ieee80211_i.h	2007-06-21 23:42:31.898638003 +0200
+++ wireless-dev/net/mac80211/ieee80211_i.h	2007-06-21 23:43:44.138638003 +0200
@@ -803,8 +803,6 @@ void ieee80211_tx_set_iswep(struct ieee8
 int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
 void ieee80211_if_setup(struct net_device *dev);
 void ieee80211_if_mgmt_setup(struct net_device *dev);
-int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
-				 const char *name);
 struct net_device_stats *ieee80211_dev_stats(struct net_device *dev);
 struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
 					  int phymode, int hwrate);
--- wireless-dev.orig/net/mac80211/ieee80211_rate.c	2007-06-21 23:41:37.238638003 +0200
+++ wireless-dev/net/mac80211/ieee80211_rate.c	2007-06-21 23:44:56.968638003 +0200
@@ -9,6 +9,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/rtnetlink.h>
 #include "ieee80211_rate.h"
 #include "ieee80211_i.h"
 
@@ -138,3 +139,44 @@ void rate_control_put(struct rate_contro
 {
 	kref_put(&ref->kref, rate_control_release);
 }
+
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+				 const char *name)
+{
+	struct rate_control_ref *ref, *old;
+
+	ASSERT_RTNL();
+	if (local->open_count || netif_running(local->mdev) ||
+	    (local->apdev && netif_running(local->apdev)))
+		return -EBUSY;
+
+	ref = rate_control_alloc(name, local);
+	if (!ref) {
+		printk(KERN_WARNING "%s: Failed to select rate control "
+		       "algorithm\n", local->mdev->name);
+		return -ENOENT;
+	}
+
+	old = local->rate_ctrl;
+	local->rate_ctrl = ref;
+	if (old) {
+		rate_control_put(old);
+		sta_info_flush(local, NULL);
+	}
+
+	printk(KERN_DEBUG "%s: Selected rate control "
+	       "algorithm '%s'\n", local->mdev->name,
+	       ref->ops->name);
+
+
+	return 0;
+}
+
+void rate_control_deinitialize(struct ieee80211_local *local)
+{
+	struct rate_control_ref *ref;
+
+	ref = local->rate_ctrl;
+	local->rate_ctrl = NULL;
+	rate_control_put(ref);
+}
--- wireless-dev.orig/net/mac80211/ieee80211_rate.h	2007-06-21 23:42:58.208638003 +0200
+++ wireless-dev/net/mac80211/ieee80211_rate.h	2007-06-21 23:43:54.298638003 +0200
@@ -141,4 +141,10 @@ static inline void rate_control_remove_s
 #endif
 }
 
+
+/* functions for rate control related to a device */
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+				 const char *name);
+void rate_control_deinitialize(struct ieee80211_local *local);
+
 #endif /* IEEE80211_RATE_H */

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 13/14] mac80211: reorder interface related functions
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (9 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 12/14] mac80211: move some rate control functions out of ieee80211.c Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-21 22:16 ` [PATCH 14/14] mac80211: introduce util.c Johannes Berg
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

This patch groups a whole bunch of functions together to make
ieee80211.c more maintainable.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/ieee80211.c | 1717 +++++++++++++++++++++++------------------------
 1 file changed, 863 insertions(+), 854 deletions(-)

--- wireless-dev.orig/net/mac80211/ieee80211.c	2007-06-21 23:48:23.248638003 +0200
+++ wireless-dev/net/mac80211/ieee80211.c	2007-06-22 00:00:58.028638003 +0200
@@ -62,94 +62,191 @@ struct ieee80211_tx_status_rtap_hdr {
 } __attribute__ ((packed));
 
 
-static int rate_list_match(const int *rate_list, int rate)
-{
-	int i;
 
-	if (!rate_list)
-		return 0;
+/* common interface routines */
 
-	for (i = 0; rate_list[i] >= 0; i++)
-		if (rate_list[i] == rate)
-			return 1;
+static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata;
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	return &(sdata->stats);
+}
 
-	return 0;
+static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
+{
+	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+	return ETH_ALEN;
 }
 
+/* master interface */
 
-void ieee80211_prepare_rates(struct ieee80211_local *local,
-			     struct ieee80211_hw_mode *mode)
+static int ieee80211_master_open(struct net_device *dev)
 {
-	int i;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	int res = -EOPNOTSUPP;
 
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		if (sdata->dev != dev && netif_running(sdata->dev)) {
+			res = 0;
+			break;
+		}
+	}
+	read_unlock(&local->sub_if_lock);
+	return res;
+}
 
-		rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
-				 IEEE80211_RATE_BASIC);
+static int ieee80211_master_stop(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
 
-		if (local->supp_rates[mode->mode]) {
-			if (!rate_list_match(local->supp_rates[mode->mode],
-					     rate->rate))
-				continue;
-		}
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list)
+		if (sdata->dev != dev && netif_running(sdata->dev))
+			dev_close(sdata->dev);
+	read_unlock(&local->sub_if_lock);
 
-		rate->flags |= IEEE80211_RATE_SUPPORTED;
+	return 0;
+}
 
-		/* Use configured basic rate set if it is available. If not,
-		 * use defaults that are sane for most cases. */
-		if (local->basic_rates[mode->mode]) {
-			if (rate_list_match(local->basic_rates[mode->mode],
-					    rate->rate))
-				rate->flags |= IEEE80211_RATE_BASIC;
-		} else switch (mode->mode) {
+/* management interface */
+
+static void
+ieee80211_fill_frame_info(struct ieee80211_local *local,
+			  struct ieee80211_frame_info *fi,
+			  struct ieee80211_rx_status *status)
+{
+	if (status) {
+		struct timespec ts;
+		struct ieee80211_rate *rate;
+
+		jiffies_to_timespec(jiffies, &ts);
+		fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
+					   ts.tv_nsec / 1000);
+		fi->mactime = cpu_to_be64(status->mactime);
+		switch (status->phymode) {
 		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_BASIC;
+			fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a);
 			break;
 		case MODE_IEEE80211B:
-			if (rate->rate == 10 || rate->rate == 20)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_ATHEROS_TURBO:
-			if (rate->rate == 120 || rate->rate == 240 ||
-			    rate->rate == 480)
-				rate->flags |= IEEE80211_RATE_BASIC;
+			fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b);
 			break;
 		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		}
-
-		/* Set ERP and MANDATORY flags based on phymode */
-		switch (mode->mode) {
-		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case MODE_IEEE80211B:
-			if (rate->rate == 10)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
+			fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g);
 			break;
 		case MODE_ATHEROS_TURBO:
+			fi->phytype =
+				htonl(ieee80211_phytype_dsss_dot11_turbo);
 			break;
-		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110 ||
-			    rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
+		default:
+			fi->phytype = htonl(0xAAAAAAAA);
 			break;
 		}
-		if (ieee80211_is_erp_rate(mode->mode, rate->rate))
-			rate->flags |= IEEE80211_RATE_ERP;
+		fi->channel = htonl(status->channel);
+		rate = ieee80211_get_rate(local, status->phymode,
+					  status->rate);
+		if (rate) {
+			fi->datarate = htonl(rate->rate);
+			if (rate->flags & IEEE80211_RATE_PREAMBLE2) {
+				if (status->rate == rate->val)
+					fi->preamble = htonl(2); /* long */
+				else if (status->rate == rate->val2)
+					fi->preamble = htonl(1); /* short */
+			} else
+				fi->preamble = htonl(0);
+		} else {
+			fi->datarate = htonl(0);
+			fi->preamble = htonl(0);
+		}
+
+		fi->antenna = htonl(status->antenna);
+		fi->priority = htonl(0xffffffff); /* no clue */
+		fi->ssi_type = htonl(ieee80211_ssi_raw);
+		fi->ssi_signal = htonl(status->ssi);
+		fi->ssi_noise = 0x00000000;
+		fi->encoding = 0;
+	} else {
+		/* clear everything because we really don't know.
+		 * the msg_type field isn't present on monitor frames
+		 * so we don't know whether it will be present or not,
+		 * but it's ok to not clear it since it'll be assigned
+		 * anyway */
+		memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type));
+
+		fi->ssi_type = htonl(ieee80211_ssi_none);
+	}
+	fi->version = htonl(IEEE80211_FI_VERSION);
+	fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type));
+}
+
+/* this routine is actually not just for this, but also
+ * for pushing fake 'management' frames into userspace.
+ * it shall be replaced by a netlink-based system. */
+void
+ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
+		  struct ieee80211_rx_status *status, u32 msg_type)
+{
+	struct ieee80211_frame_info *fi;
+	const size_t hlen = sizeof(struct ieee80211_frame_info);
+	struct ieee80211_sub_if_data *sdata;
+
+	skb->dev = local->apdev;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev);
+
+	if (skb_headroom(skb) < hlen) {
+		I802_DEBUG_INC(local->rx_expand_skb_head);
+		if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			return;
+		}
 	}
+
+	fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+
+	ieee80211_fill_frame_info(local, fi, status);
+	fi->msg_type = htonl(msg_type);
+
+	sdata->stats.rx_packets++;
+	sdata->stats.rx_bytes += skb->len;
+
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+	memset(skb->cb, 0, sizeof(skb->cb));
+	netif_rx(skb);
 }
 
+int ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
+			   int radar, int radar_type)
+{
+	struct sk_buff *skb;
+	struct ieee80211_radar_info *msg;
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (!local->apdev)
+		return 0;
+
+	skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
+			    sizeof(struct ieee80211_radar_info));
+
+	if (!skb)
+		return -ENOMEM;
+	skb_reserve(skb, sizeof(struct ieee80211_frame_info));
+
+	msg = (struct ieee80211_radar_info *)
+		skb_put(skb, sizeof(struct ieee80211_radar_info));
+	msg->channel = channel;
+	msg->radar = radar;
+	msg->radar_type = radar_type;
+
+	ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar);
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_radar_status);
 
 void ieee80211_key_threshold_notify(struct net_device *dev,
 				    struct ieee80211_key *key,
@@ -186,749 +283,860 @@ void ieee80211_key_threshold_notify(stru
 			  ieee80211_msg_key_threshold_notification);
 }
 
+static int ieee80211_mgmt_open(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
+	if (!netif_running(local->mdev))
+		return -EOPNOTSUPP;
+	return 0;
+}
+
+static int ieee80211_mgmt_stop(struct net_device *dev)
 {
-	u16 fc;
+	return 0;
+}
 
-	if (len < 24)
-		return NULL;
+static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu)
+{
+	/* FIX: what would be proper limits for MTU?
+	 * This interface uses 802.11 frames. */
+	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) {
+		printk(KERN_WARNING "%s: invalid MTU %d\n",
+		       dev->name, new_mtu);
+		return -EINVAL;
+	}
 
-	fc = le16_to_cpu(hdr->frame_control);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	dev->mtu = new_mtu;
+	return 0;
+}
 
-	switch (fc & IEEE80211_FCTL_FTYPE) {
-	case IEEE80211_FTYPE_DATA:
-		switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-		case IEEE80211_FCTL_TODS:
-			return hdr->addr1;
-		case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-			return NULL;
-		case IEEE80211_FCTL_FROMDS:
-			return hdr->addr2;
-		case 0:
-			return hdr->addr3;
-		}
-		break;
-	case IEEE80211_FTYPE_MGMT:
-		return hdr->addr3;
-	case IEEE80211_FTYPE_CTL:
-		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
-			return hdr->addr1;
-		else
-			return NULL;
+void ieee80211_if_mgmt_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+	dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
+	dev->change_mtu = ieee80211_change_mtu_apdev;
+	dev->get_stats = ieee80211_get_stats;
+	dev->open = ieee80211_mgmt_open;
+	dev->stop = ieee80211_mgmt_stop;
+	dev->type = ARPHRD_IEEE80211_PRISM;
+	dev->hard_header_parse = header_parse_80211;
+	dev->uninit = ieee80211_if_reinit;
+	dev->destructor = ieee80211_if_free;
+}
+
+
+/* regular interfaces */
+
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* FIX: what would be proper limits for MTU?
+	 * This interface uses 802.3 frames. */
+	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
+		printk(KERN_WARNING "%s: invalid MTU %d\n",
+		       dev->name, new_mtu);
+		return -EINVAL;
 	}
 
-	return NULL;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	dev->mtu = new_mtu;
+	return 0;
 }
 
-int ieee80211_get_hdrlen(u16 fc)
+static inline int identical_mac_addr_allowed(int type1, int type2)
 {
-	int hdrlen = 24;
+	return (type1 == IEEE80211_IF_TYPE_MNTR ||
+		type2 == IEEE80211_IF_TYPE_MNTR ||
+		(type1 == IEEE80211_IF_TYPE_AP &&
+		 type2 == IEEE80211_IF_TYPE_WDS) ||
+		(type1 == IEEE80211_IF_TYPE_WDS &&
+		 (type2 == IEEE80211_IF_TYPE_WDS ||
+		  type2 == IEEE80211_IF_TYPE_AP)) ||
+		(type1 == IEEE80211_IF_TYPE_AP &&
+		 type2 == IEEE80211_IF_TYPE_VLAN) ||
+		(type1 == IEEE80211_IF_TYPE_VLAN &&
+		 (type2 == IEEE80211_IF_TYPE_AP ||
+		  type2 == IEEE80211_IF_TYPE_VLAN)));
+}
 
-	switch (fc & IEEE80211_FCTL_FTYPE) {
-	case IEEE80211_FTYPE_DATA:
-		if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
-			hdrlen = 30; /* Addr4 */
-		/*
-		 * The QoS Control field is two bytes and its presence is
-		 * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
-		 * hdrlen if that bit is set.
-		 * This works by masking out the bit and shifting it to
-		 * bit position 1 so the result has the value 0 or 2.
-		 */
-		hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
-				>> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
-		break;
-	case IEEE80211_FTYPE_CTL:
-		/*
-		 * ACK and CTS are 10 bytes, all others 16. To see how
-		 * to get this condition consider
-		 *   subtype mask:   0b0000000011110000 (0x00F0)
-		 *   ACK subtype:    0b0000000011010000 (0x00D0)
-		 *   CTS subtype:    0b0000000011000000 (0x00C0)
-		 *   bits that matter:         ^^^      (0x00E0)
-		 *   value of those: 0b0000000011000000 (0x00C0)
-		 */
-		if ((fc & 0xE0) == 0xC0)
-			hdrlen = 10;
-		else
-			hdrlen = 16;
-		break;
-	}
+/* Check if running monitor interfaces should go to a "soft monitor" mode
+ * and switch them if necessary. */
+static void ieee80211_start_soft_monitor(struct ieee80211_local *local)
+{
+	struct ieee80211_if_init_conf conf;
 
-	return hdrlen;
+	if (local->open_count && local->open_count == local->monitors &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
+	    local->ops->remove_interface) {
+		conf.if_id = -1;
+		conf.type = IEEE80211_IF_TYPE_MNTR;
+		conf.mac_addr = NULL;
+		local->ops->remove_interface(local_to_hw(local), &conf);
+	}
 }
-EXPORT_SYMBOL(ieee80211_get_hdrlen);
 
-int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
+/* Check if running monitor interfaces should go to a "hard monitor" mode
+ * and switch them if necessary. */
+static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
 {
-	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
-	int hdrlen;
+	struct ieee80211_if_init_conf conf;
 
-	if (unlikely(skb->len < 10))
-		return 0;
-	hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
-	if (unlikely(hdrlen > skb->len))
-		return 0;
-	return hdrlen;
+	if (local->open_count && local->open_count == local->monitors &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
+		conf.if_id = -1;
+		conf.type = IEEE80211_IF_TYPE_MNTR;
+		conf.mac_addr = NULL;
+		local->ops->add_interface(local_to_hw(local), &conf);
+	}
 }
-EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 
-
-int ieee80211_is_eapol(const struct sk_buff *skb)
+static int ieee80211_open(struct net_device *dev)
 {
-	const struct ieee80211_hdr *hdr;
-	u16 fc;
-	int hdrlen;
+	struct ieee80211_sub_if_data *sdata, *nsdata;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_if_init_conf conf;
+	int res;
 
-	if (unlikely(skb->len < 10))
-		return 0;
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(nsdata, &local->sub_if_list, list) {
+		struct net_device *ndev = nsdata->dev;
 
-	hdr = (const struct ieee80211_hdr *) skb->data;
-	fc = le16_to_cpu(hdr->frame_control);
+		if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
+		    compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 &&
+		    !identical_mac_addr_allowed(sdata->type, nsdata->type)) {
+			read_unlock(&local->sub_if_lock);
+			return -ENOTUNIQ;
+		}
+	}
+	read_unlock(&local->sub_if_lock);
 
-	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+	if (sdata->type == IEEE80211_IF_TYPE_WDS &&
+	    is_zero_ether_addr(sdata->u.wds.remote_addr))
+		return -ENOLINK;
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
+		/* run the interface in a "soft monitor" mode */
+		local->monitors++;
+		local->open_count++;
+		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
 		return 0;
+	}
+	ieee80211_start_soft_monitor(local);
 
-	hdrlen = ieee80211_get_hdrlen(fc);
+	conf.if_id = dev->ifindex;
+	conf.type = sdata->type;
+	conf.mac_addr = dev->dev_addr;
+	res = local->ops->add_interface(local_to_hw(local), &conf);
+	if (res) {
+		if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+			ieee80211_start_hard_monitor(local);
+		return res;
+	}
 
-	if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
-		     memcmp(skb->data + hdrlen, eapol_header,
-			    sizeof(eapol_header)) == 0))
-		return 1;
+	if (local->open_count == 0) {
+		res = 0;
+		tasklet_enable(&local->tx_pending_tasklet);
+		tasklet_enable(&local->tasklet);
+		if (local->ops->open)
+			res = local->ops->open(local_to_hw(local));
+		if (res == 0) {
+			res = dev_open(local->mdev);
+			if (res) {
+				if (local->ops->stop)
+					local->ops->stop(local_to_hw(local));
+			} else {
+				res = ieee80211_hw_config(local);
+				if (res && local->ops->stop)
+					local->ops->stop(local_to_hw(local));
+				else if (!res && local->apdev)
+					dev_open(local->apdev);
+			}
+		}
+		if (res) {
+			if (local->ops->remove_interface)
+				local->ops->remove_interface(local_to_hw(local),
+							    &conf);
+			return res;
+		}
+	}
+	local->open_count++;
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		local->monitors++;
+		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+	} else
+		ieee80211_if_config(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA &&
+	    !local->user_space_mlme)
+		netif_carrier_off(dev);
+	else
+		netif_carrier_on(dev);
 
+	netif_start_queue(dev);
 	return 0;
 }
 
-
-void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
+static void ieee80211_if_shutdown(struct net_device *dev)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-	if (tx->u.tx.extra_frag) {
-		struct ieee80211_hdr *fhdr;
-		int i;
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-			fhdr = (struct ieee80211_hdr *)
-				tx->u.tx.extra_frag[i]->data;
-			fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	ASSERT_RTNL();
+	switch (sdata->type) {
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+		sdata->u.sta.state = IEEE80211_DISABLED;
+		del_timer_sync(&sdata->u.sta.timer);
+		del_timer_sync(&sdata->u.sta.admit_timer);
+		skb_queue_purge(&sdata->u.sta.skb_queue);
+		if (!local->ops->hw_scan &&
+		    local->scan_dev == sdata->dev) {
+			local->sta_scanning = 0;
+			cancel_delayed_work(&local->scan_work);
 		}
+		flush_workqueue(local->hw.workqueue);
+		break;
 	}
 }
 
-
-int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
-			     int rate, int erp, int short_preamble)
+static int ieee80211_stop(struct net_device *dev)
 {
-	int dur;
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-	/* calculate duration (in microseconds, rounded up to next higher
-	 * integer if it includes a fractional microsecond) to send frame of
-	 * len bytes (does not include FCS) at the given rate. Duration will
-	 * also include SIFS.
-	 *
-	 * rate is in 100 kbps, so divident is multiplied by 10 in the
-	 * DIV_ROUND_UP() operations.
-	 */
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (local->hw.conf.phymode == MODE_IEEE80211A || erp ||
-	    local->hw.conf.phymode == MODE_ATHEROS_TURBO) {
-		/*
-		 * OFDM:
-		 *
-		 * N_DBPS = DATARATE x 4
-		 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
-		 *	(16 = SIGNAL time, 6 = tail bits)
-		 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
-		 *
-		 * T_SYM = 4 usec
-		 * 802.11a - 17.5.2: aSIFSTime = 16 usec
-		 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
-		 *	signal ext = 6 usec
-		 */
-		/* FIX: Atheros Turbo may have different (shorter) duration? */
-		dur = 16; /* SIFS + signal ext */
-		dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
-		dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
-		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
-					4 * rate); /* T_SYM x N_SYM */
-	} else {
-		/*
-		 * 802.11b or 802.11g with 802.11b compatibility:
-		 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
-		 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
-		 *
-		 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
-		 * aSIFSTime = 10 usec
-		 * aPreambleLength = 144 usec or 72 usec with short preamble
-		 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
-		 */
-		dur = 10; /* aSIFSTime = 10 usec */
-		dur += short_preamble ? (72 + 24) : (144 + 48);
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
+	    local->open_count > 1 &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
+		/* remove "soft monitor" interface */
+		local->open_count--;
+		local->monitors--;
+		if (!local->monitors)
+			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+		return 0;
+	}
 
-		dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
+	netif_stop_queue(dev);
+	ieee80211_if_shutdown(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		local->monitors--;
+		if (!local->monitors)
+			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
 	}
 
-	return dur;
+	local->open_count--;
+	if (local->open_count == 0) {
+		if (netif_running(local->mdev))
+			dev_close(local->mdev);
+		if (local->apdev)
+			dev_close(local->apdev);
+		if (local->ops->stop)
+			local->ops->stop(local_to_hw(local));
+		tasklet_disable(&local->tx_pending_tasklet);
+		tasklet_disable(&local->tasklet);
+	}
+	if (local->ops->remove_interface) {
+		struct ieee80211_if_init_conf conf;
+
+		conf.if_id = dev->ifindex;
+		conf.type = sdata->type;
+		conf.mac_addr = dev->dev_addr;
+		local->ops->remove_interface(local_to_hw(local), &conf);
+	}
+
+	ieee80211_start_hard_monitor(local);
+
+	return 0;
 }
 
+enum netif_tx_lock_class {
+	TX_LOCK_NORMAL,
+	TX_LOCK_MASTER,
+};
 
-/* Exported duration function for driver use */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
-					size_t frame_len, int rate)
+static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
-	u16 dur;
-	int erp;
+	spin_lock_nested(&dev->_xmit_lock, subclass);
+	dev->xmit_lock_owner = smp_processor_id();
+}
 
-	erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
-	dur = ieee80211_frame_duration(local, frame_len, rate,
-				       erp, local->short_preamble);
+static void ieee80211_set_multicast_list(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	unsigned short flags;
 
-	return cpu_to_le16(dur);
+	netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
+	if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
+		if (sdata->allmulti) {
+			sdata->allmulti = 0;
+			local->iff_allmultis--;
+		} else {
+			sdata->allmulti = 1;
+			local->iff_allmultis++;
+		}
+	}
+	if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
+		if (sdata->promisc) {
+			sdata->promisc = 0;
+			local->iff_promiscs--;
+		} else {
+			sdata->promisc = 1;
+			local->iff_promiscs++;
+		}
+	}
+	if (dev->mc_count != sdata->mc_count) {
+		local->mc_count = local->mc_count - sdata->mc_count +
+				  dev->mc_count;
+		sdata->mc_count = dev->mc_count;
+	}
+	if (local->ops->set_multicast_list) {
+		flags = local->mdev->flags;
+		if (local->iff_allmultis)
+			flags |= IFF_ALLMULTI;
+		if (local->iff_promiscs)
+			flags |= IFF_PROMISC;
+		read_lock(&local->sub_if_lock);
+		local->ops->set_multicast_list(local_to_hw(local), flags,
+					      local->mc_count);
+		read_unlock(&local->sub_if_lock);
+	}
+	netif_tx_unlock(local->mdev);
 }
-EXPORT_SYMBOL(ieee80211_generic_frame_duration);
 
+/* Must not be called for mdev and apdev */
+void ieee80211_if_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+	dev->hard_start_xmit = ieee80211_subif_start_xmit;
+	dev->wireless_handlers = &ieee80211_iw_handler_def;
+	dev->do_ioctl = ieee80211_ioctl;
+	dev->set_multicast_list = ieee80211_set_multicast_list;
+	dev->change_mtu = ieee80211_change_mtu;
+	dev->get_stats = ieee80211_get_stats;
+	dev->open = ieee80211_open;
+	dev->stop = ieee80211_stop;
+	dev->uninit = ieee80211_if_reinit;
+	dev->destructor = ieee80211_if_free;
+}
 
-__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
-			      size_t frame_len,
-			      const struct ieee80211_tx_control *frame_txctl)
+
+/* WDS specialties */
+int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_rate *rate;
-	int short_preamble = local->short_preamble;
-	int erp;
-	u16 dur;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
 
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+	if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
+		return 0;
 
-	/* CTS duration */
-	dur = ieee80211_frame_duration(local, 10, rate->rate,
-				       erp, short_preamble);
-	/* Data frame duration */
-	dur += ieee80211_frame_duration(local, frame_len, rate->rate,
-					erp, short_preamble);
-	/* ACK duration */
-	dur += ieee80211_frame_duration(local, 10, rate->rate,
-					erp, short_preamble);
+	/* Create STA entry for the new peer */
+	sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
+	if (!sta)
+		return -ENOMEM;
+	sta_info_put(sta);
 
-	return cpu_to_le16(dur);
+	/* Remove STA entry for the old peer */
+	sta = sta_info_get(local, sdata->u.wds.remote_addr);
+	if (sta) {
+		sta_info_put(sta);
+		sta_info_free(sta, 0);
+	} else {
+		printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
+		       "peer " MAC_FMT "\n",
+		       dev->name, MAC_ARG(sdata->u.wds.remote_addr));
+	}
+
+	/* Update WDS link data */
+	memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
+
+	return 0;
 }
-EXPORT_SYMBOL(ieee80211_rts_duration);
 
 
-__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
-				    size_t frame_len,
-				    const struct ieee80211_tx_control *frame_txctl)
+/* everything else */
+
+static int rate_list_match(const int *rate_list, int rate)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_rate *rate;
-	int short_preamble = local->short_preamble;
-	int erp;
-	u16 dur;
+	int i;
 
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+	if (!rate_list)
+		return 0;
 
-	/* Data frame duration */
-	dur = ieee80211_frame_duration(local, frame_len, rate->rate,
-				       erp, short_preamble);
-	if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
-		/* ACK duration */
-		dur += ieee80211_frame_duration(local, 10, rate->rate,
-						erp, short_preamble);
-	}
+	for (i = 0; rate_list[i] >= 0; i++)
+		if (rate_list[i] == rate)
+			return 1;
 
-	return cpu_to_le16(dur);
+	return 0;
 }
-EXPORT_SYMBOL(ieee80211_ctstoself_duration);
 
 
-static int __ieee80211_if_config(struct net_device *dev,
-				 struct sk_buff *beacon,
-				 struct ieee80211_tx_control *control)
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+			     struct ieee80211_hw_mode *mode)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_if_conf conf;
-	static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	int i;
 
-	if (!local->ops->config_interface || !netif_running(dev))
-		return 0;
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *rate = &mode->rates[i];
 
-	memset(&conf, 0, sizeof(conf));
-	conf.type = sdata->type;
-	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
-		if (local->sta_scanning &&
-		    local->scan_dev == dev)
-			conf.bssid = scan_bssid;
-		else
-			conf.bssid = sdata->u.sta.bssid;
-		conf.ssid = sdata->u.sta.ssid;
-		conf.ssid_len = sdata->u.sta.ssid_len;
-		conf.generic_elem = sdata->u.sta.extra_ie;
-		conf.generic_elem_len = sdata->u.sta.extra_ie_len;
-	} else if (sdata->type == IEEE80211_IF_TYPE_AP) {
-		conf.ssid = sdata->u.ap.ssid;
-		conf.ssid_len = sdata->u.ap.ssid_len;
-		conf.generic_elem = sdata->u.ap.generic_elem;
-		conf.generic_elem_len = sdata->u.ap.generic_elem_len;
-		conf.beacon = beacon;
-		conf.beacon_control = control;
-	}
-	return local->ops->config_interface(local_to_hw(local),
-					   dev->ifindex, &conf);
-}
+		rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
+				 IEEE80211_RATE_BASIC);
 
-int ieee80211_if_config(struct net_device *dev)
-{
-	return __ieee80211_if_config(dev, NULL, NULL);
-}
+		if (local->supp_rates[mode->mode]) {
+			if (!rate_list_match(local->supp_rates[mode->mode],
+					     rate->rate))
+				continue;
+		}
 
-int ieee80211_if_config_beacon(struct net_device *dev)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_tx_control control;
-	struct sk_buff *skb;
+		rate->flags |= IEEE80211_RATE_SUPPORTED;
 
-	if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
-		return 0;
-	skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
-	if (!skb)
-		return -ENOMEM;
-	return __ieee80211_if_config(dev, skb, &control);
+		/* Use configured basic rate set if it is available. If not,
+		 * use defaults that are sane for most cases. */
+		if (local->basic_rates[mode->mode]) {
+			if (rate_list_match(local->basic_rates[mode->mode],
+					    rate->rate))
+				rate->flags |= IEEE80211_RATE_BASIC;
+		} else switch (mode->mode) {
+		case MODE_IEEE80211A:
+			if (rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_IEEE80211B:
+			if (rate->rate == 10 || rate->rate == 20)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_ATHEROS_TURBO:
+			if (rate->rate == 120 || rate->rate == 240 ||
+			    rate->rate == 480)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_IEEE80211G:
+			if (rate->rate == 10 || rate->rate == 20 ||
+			    rate->rate == 55 || rate->rate == 110)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		}
+
+		/* Set ERP and MANDATORY flags based on phymode */
+		switch (mode->mode) {
+		case MODE_IEEE80211A:
+			if (rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		case MODE_IEEE80211B:
+			if (rate->rate == 10)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		case MODE_ATHEROS_TURBO:
+			break;
+		case MODE_IEEE80211G:
+			if (rate->rate == 10 || rate->rate == 20 ||
+			    rate->rate == 55 || rate->rate == 110 ||
+			    rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		}
+		if (ieee80211_is_erp_rate(mode->mode, rate->rate))
+			rate->flags |= IEEE80211_RATE_ERP;
+	}
 }
 
-int ieee80211_hw_config(struct ieee80211_local *local)
-{
-	struct ieee80211_hw_mode *mode;
-	struct ieee80211_channel *chan;
-	int ret = 0;
 
-	if (local->sta_scanning) {
-		chan = local->scan_channel;
-		mode = local->scan_hw_mode;
-	} else {
-		chan = local->oper_channel;
-		mode = local->oper_hw_mode;
-	}
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc;
 
-	local->hw.conf.channel = chan->chan;
-	local->hw.conf.channel_val = chan->val;
-	local->hw.conf.power_level = chan->power_level;
-	local->hw.conf.freq = chan->freq;
-	local->hw.conf.phymode = mode->mode;
-	local->hw.conf.antenna_max = chan->antenna_max;
-	local->hw.conf.chan = chan;
-	local->hw.conf.mode = mode;
+	if (len < 24)
+		return NULL;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
-	       "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
-	       local->hw.conf.phymode);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	fc = le16_to_cpu(hdr->frame_control);
 
-	if (local->ops->config)
-		ret = local->ops->config(local_to_hw(local), &local->hw.conf);
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+		case IEEE80211_FCTL_TODS:
+			return hdr->addr1;
+		case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+			return NULL;
+		case IEEE80211_FCTL_FROMDS:
+			return hdr->addr2;
+		case 0:
+			return hdr->addr3;
+		}
+		break;
+	case IEEE80211_FTYPE_MGMT:
+		return hdr->addr3;
+	case IEEE80211_FTYPE_CTL:
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
+			return hdr->addr1;
+		else
+			return NULL;
+	}
 
-	return ret;
+	return NULL;
 }
 
-
-static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+int ieee80211_get_hdrlen(u16 fc)
 {
-	/* FIX: what would be proper limits for MTU?
-	 * This interface uses 802.3 frames. */
-	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
-		printk(KERN_WARNING "%s: invalid MTU %d\n",
-		       dev->name, new_mtu);
-		return -EINVAL;
+	int hdrlen = 24;
+
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+			hdrlen = 30; /* Addr4 */
+		/*
+		 * The QoS Control field is two bytes and its presence is
+		 * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
+		 * hdrlen if that bit is set.
+		 * This works by masking out the bit and shifting it to
+		 * bit position 1 so the result has the value 0 or 2.
+		 */
+		hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
+				>> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
+		break;
+	case IEEE80211_FTYPE_CTL:
+		/*
+		 * ACK and CTS are 10 bytes, all others 16. To see how
+		 * to get this condition consider
+		 *   subtype mask:   0b0000000011110000 (0x00F0)
+		 *   ACK subtype:    0b0000000011010000 (0x00D0)
+		 *   CTS subtype:    0b0000000011000000 (0x00C0)
+		 *   bits that matter:         ^^^      (0x00E0)
+		 *   value of those: 0b0000000011000000 (0x00C0)
+		 */
+		if ((fc & 0xE0) == 0xC0)
+			hdrlen = 10;
+		else
+			hdrlen = 16;
+		break;
 	}
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-	dev->mtu = new_mtu;
-	return 0;
+	return hdrlen;
 }
+EXPORT_SYMBOL(ieee80211_get_hdrlen);
 
-
-static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu)
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 {
-	/* FIX: what would be proper limits for MTU?
-	 * This interface uses 802.11 frames. */
-	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) {
-		printk(KERN_WARNING "%s: invalid MTU %d\n",
-		       dev->name, new_mtu);
-		return -EINVAL;
-	}
+	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
+	int hdrlen;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-	dev->mtu = new_mtu;
-	return 0;
+	if (unlikely(skb->len < 10))
+		return 0;
+	hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+	if (unlikely(hdrlen > skb->len))
+		return 0;
+	return hdrlen;
 }
+EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 
-enum netif_tx_lock_class {
-	TX_LOCK_NORMAL,
-	TX_LOCK_MASTER,
-};
 
-static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
+int ieee80211_is_eapol(const struct sk_buff *skb)
 {
-	spin_lock_nested(&dev->_xmit_lock, subclass);
-	dev->xmit_lock_owner = smp_processor_id();
-}
+	const struct ieee80211_hdr *hdr;
+	u16 fc;
+	int hdrlen;
 
-static void ieee80211_set_multicast_list(struct net_device *dev)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	unsigned short flags;
+	if (unlikely(skb->len < 10))
+		return 0;
 
-	netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
-	if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
-		if (sdata->allmulti) {
-			sdata->allmulti = 0;
-			local->iff_allmultis--;
-		} else {
-			sdata->allmulti = 1;
-			local->iff_allmultis++;
-		}
-	}
-	if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
-		if (sdata->promisc) {
-			sdata->promisc = 0;
-			local->iff_promiscs--;
-		} else {
-			sdata->promisc = 1;
-			local->iff_promiscs++;
-		}
-	}
-	if (dev->mc_count != sdata->mc_count) {
-		local->mc_count = local->mc_count - sdata->mc_count +
-				  dev->mc_count;
-		sdata->mc_count = dev->mc_count;
-	}
-	if (local->ops->set_multicast_list) {
-		flags = local->mdev->flags;
-		if (local->iff_allmultis)
-			flags |= IFF_ALLMULTI;
-		if (local->iff_promiscs)
-			flags |= IFF_PROMISC;
-		read_lock(&local->sub_if_lock);
-		local->ops->set_multicast_list(local_to_hw(local), flags,
-					      local->mc_count);
-		read_unlock(&local->sub_if_lock);
-	}
-	netif_tx_unlock(local->mdev);
-}
+	hdr = (const struct ieee80211_hdr *) skb->data;
+	fc = le16_to_cpu(hdr->frame_control);
 
-struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
-					       struct dev_mc_list *prev,
-					       void **ptr)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_sub_if_data *sdata = *ptr;
-	struct dev_mc_list *mc;
+	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+		return 0;
 
-	if (!prev) {
-		WARN_ON(sdata);
-		sdata = NULL;
-	}
-	if (!prev || !prev->next) {
-		if (sdata)
-			sdata = list_entry(sdata->list.next,
-					   struct ieee80211_sub_if_data, list);
-		else
-			sdata = list_entry(local->sub_if_list.next,
-					   struct ieee80211_sub_if_data, list);
-		if (&sdata->list != &local->sub_if_list)
-			mc = sdata->dev->mc_list;
-		else
-			mc = NULL;
-	} else
-		mc = prev->next;
+	hdrlen = ieee80211_get_hdrlen(fc);
 
-	*ptr = sdata;
-	return mc;
-}
-EXPORT_SYMBOL(ieee80211_get_mc_list_item);
+	if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
+		     memcmp(skb->data + hdrlen, eapol_header,
+			    sizeof(eapol_header)) == 0))
+		return 1;
 
-static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata;
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	return &(sdata->stats);
+	return 0;
 }
 
-static void ieee80211_if_shutdown(struct net_device *dev)
+
+void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
 
-	ASSERT_RTNL();
-	switch (sdata->type) {
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-		sdata->u.sta.state = IEEE80211_DISABLED;
-		del_timer_sync(&sdata->u.sta.timer);
-		del_timer_sync(&sdata->u.sta.admit_timer);
-		skb_queue_purge(&sdata->u.sta.skb_queue);
-		if (!local->ops->hw_scan &&
-		    local->scan_dev == sdata->dev) {
-			local->sta_scanning = 0;
-			cancel_delayed_work(&local->scan_work);
+	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	if (tx->u.tx.extra_frag) {
+		struct ieee80211_hdr *fhdr;
+		int i;
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			fhdr = (struct ieee80211_hdr *)
+				tx->u.tx.extra_frag[i]->data;
+			fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 		}
-		flush_workqueue(local->hw.workqueue);
-		break;
 	}
 }
 
-static inline int identical_mac_addr_allowed(int type1, int type2)
-{
-	return (type1 == IEEE80211_IF_TYPE_MNTR ||
-		type2 == IEEE80211_IF_TYPE_MNTR ||
-		(type1 == IEEE80211_IF_TYPE_AP &&
-		 type2 == IEEE80211_IF_TYPE_WDS) ||
-		(type1 == IEEE80211_IF_TYPE_WDS &&
-		 (type2 == IEEE80211_IF_TYPE_WDS ||
-		  type2 == IEEE80211_IF_TYPE_AP)) ||
-		(type1 == IEEE80211_IF_TYPE_AP &&
-		 type2 == IEEE80211_IF_TYPE_VLAN) ||
-		(type1 == IEEE80211_IF_TYPE_VLAN &&
-		 (type2 == IEEE80211_IF_TYPE_AP ||
-		  type2 == IEEE80211_IF_TYPE_VLAN)));
-}
 
-static int ieee80211_master_open(struct net_device *dev)
+int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+			     int rate, int erp, int short_preamble)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata;
-	int res = -EOPNOTSUPP;
+	int dur;
 
-	read_lock(&local->sub_if_lock);
-	list_for_each_entry(sdata, &local->sub_if_list, list) {
-		if (sdata->dev != dev && netif_running(sdata->dev)) {
-			res = 0;
-			break;
-		}
-	}
-	read_unlock(&local->sub_if_lock);
-	return res;
-}
+	/* calculate duration (in microseconds, rounded up to next higher
+	 * integer if it includes a fractional microsecond) to send frame of
+	 * len bytes (does not include FCS) at the given rate. Duration will
+	 * also include SIFS.
+	 *
+	 * rate is in 100 kbps, so divident is multiplied by 10 in the
+	 * DIV_ROUND_UP() operations.
+	 */
 
-static int ieee80211_master_stop(struct net_device *dev)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata;
+	if (local->hw.conf.phymode == MODE_IEEE80211A || erp ||
+	    local->hw.conf.phymode == MODE_ATHEROS_TURBO) {
+		/*
+		 * OFDM:
+		 *
+		 * N_DBPS = DATARATE x 4
+		 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
+		 *	(16 = SIGNAL time, 6 = tail bits)
+		 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
+		 *
+		 * T_SYM = 4 usec
+		 * 802.11a - 17.5.2: aSIFSTime = 16 usec
+		 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
+		 *	signal ext = 6 usec
+		 */
+		/* FIX: Atheros Turbo may have different (shorter) duration? */
+		dur = 16; /* SIFS + signal ext */
+		dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
+		dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
+		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
+					4 * rate); /* T_SYM x N_SYM */
+	} else {
+		/*
+		 * 802.11b or 802.11g with 802.11b compatibility:
+		 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
+		 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
+		 *
+		 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
+		 * aSIFSTime = 10 usec
+		 * aPreambleLength = 144 usec or 72 usec with short preamble
+		 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
+		 */
+		dur = 10; /* aSIFSTime = 10 usec */
+		dur += short_preamble ? (72 + 24) : (144 + 48);
 
-	read_lock(&local->sub_if_lock);
-	list_for_each_entry(sdata, &local->sub_if_list, list)
-		if (sdata->dev != dev && netif_running(sdata->dev))
-			dev_close(sdata->dev);
-	read_unlock(&local->sub_if_lock);
+		dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
+	}
 
-	return 0;
+	return dur;
 }
 
-static int ieee80211_mgmt_open(struct net_device *dev)
+
+/* Exported duration function for driver use */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+					size_t frame_len, int rate)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_local *local = hw_to_local(hw);
+	u16 dur;
+	int erp;
 
-	if (!netif_running(local->mdev))
-		return -EOPNOTSUPP;
-	return 0;
-}
+	erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
+	dur = ieee80211_frame_duration(local, frame_len, rate,
+				       erp, local->short_preamble);
 
-static int ieee80211_mgmt_stop(struct net_device *dev)
-{
-	return 0;
+	return cpu_to_le16(dur);
 }
+EXPORT_SYMBOL(ieee80211_generic_frame_duration);
 
-/* Check if running monitor interfaces should go to a "soft monitor" mode
- * and switch them if necessary. */
-static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
+
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+			      size_t frame_len,
+			      const struct ieee80211_tx_control *frame_txctl)
 {
-	struct ieee80211_if_init_conf conf;
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rate *rate;
+	int short_preamble = local->short_preamble;
+	int erp;
+	u16 dur;
 
-	if (local->open_count && local->open_count == local->monitors &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
-	    local->ops->remove_interface) {
-		conf.if_id = -1;
-		conf.type = IEEE80211_IF_TYPE_MNTR;
-		conf.mac_addr = NULL;
-		local->ops->remove_interface(local_to_hw(local), &conf);
-	}
-}
+	rate = frame_txctl->rts_rate;
+	erp = !!(rate->flags & IEEE80211_RATE_ERP);
 
-/* Check if running monitor interfaces should go to a "hard monitor" mode
- * and switch them if necessary. */
-static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
-{
-	struct ieee80211_if_init_conf conf;
+	/* CTS duration */
+	dur = ieee80211_frame_duration(local, 10, rate->rate,
+				       erp, short_preamble);
+	/* Data frame duration */
+	dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+					erp, short_preamble);
+	/* ACK duration */
+	dur += ieee80211_frame_duration(local, 10, rate->rate,
+					erp, short_preamble);
 
-	if (local->open_count && local->open_count == local->monitors &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		conf.if_id = -1;
-		conf.type = IEEE80211_IF_TYPE_MNTR;
-		conf.mac_addr = NULL;
-		local->ops->add_interface(local_to_hw(local), &conf);
-	}
+	return cpu_to_le16(dur);
 }
+EXPORT_SYMBOL(ieee80211_rts_duration);
 
-static int ieee80211_open(struct net_device *dev)
+
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+				    size_t frame_len,
+				    const struct ieee80211_tx_control *frame_txctl)
 {
-	struct ieee80211_sub_if_data *sdata, *nsdata;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_if_init_conf conf;
-	int res;
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rate *rate;
+	int short_preamble = local->short_preamble;
+	int erp;
+	u16 dur;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	read_lock(&local->sub_if_lock);
-	list_for_each_entry(nsdata, &local->sub_if_list, list) {
-		struct net_device *ndev = nsdata->dev;
+	rate = frame_txctl->rts_rate;
+	erp = !!(rate->flags & IEEE80211_RATE_ERP);
 
-		if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
-		    compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 &&
-		    !identical_mac_addr_allowed(sdata->type, nsdata->type)) {
-			read_unlock(&local->sub_if_lock);
-			return -ENOTUNIQ;
-		}
+	/* Data frame duration */
+	dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+				       erp, short_preamble);
+	if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+		/* ACK duration */
+		dur += ieee80211_frame_duration(local, 10, rate->rate,
+						erp, short_preamble);
 	}
-	read_unlock(&local->sub_if_lock);
 
-	if (sdata->type == IEEE80211_IF_TYPE_WDS &&
-	    is_zero_ether_addr(sdata->u.wds.remote_addr))
-		return -ENOLINK;
+	return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_duration);
 
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		/* run the interface in a "soft monitor" mode */
-		local->monitors++;
-		local->open_count++;
-		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+
+static int __ieee80211_if_config(struct net_device *dev,
+				 struct sk_buff *beacon,
+				 struct ieee80211_tx_control *control)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_if_conf conf;
+	static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	if (!local->ops->config_interface || !netif_running(dev))
 		return 0;
-	}
-	ieee80211_start_soft_monitor(local);
 
-	conf.if_id = dev->ifindex;
+	memset(&conf, 0, sizeof(conf));
 	conf.type = sdata->type;
-	conf.mac_addr = dev->dev_addr;
-	res = local->ops->add_interface(local_to_hw(local), &conf);
-	if (res) {
-		if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-			ieee80211_start_hard_monitor(local);
-		return res;
-	}
-
-	if (local->open_count == 0) {
-		res = 0;
-		tasklet_enable(&local->tx_pending_tasklet);
-		tasklet_enable(&local->tasklet);
-		if (local->ops->open)
-			res = local->ops->open(local_to_hw(local));
-		if (res == 0) {
-			res = dev_open(local->mdev);
-			if (res) {
-				if (local->ops->stop)
-					local->ops->stop(local_to_hw(local));
-			} else {
-				res = ieee80211_hw_config(local);
-				if (res && local->ops->stop)
-					local->ops->stop(local_to_hw(local));
-				else if (!res && local->apdev)
-					dev_open(local->apdev);
-			}
-		}
-		if (res) {
-			if (local->ops->remove_interface)
-				local->ops->remove_interface(local_to_hw(local),
-							    &conf);
-			return res;
-		}
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		if (local->sta_scanning &&
+		    local->scan_dev == dev)
+			conf.bssid = scan_bssid;
+		else
+			conf.bssid = sdata->u.sta.bssid;
+		conf.ssid = sdata->u.sta.ssid;
+		conf.ssid_len = sdata->u.sta.ssid_len;
+		conf.generic_elem = sdata->u.sta.extra_ie;
+		conf.generic_elem_len = sdata->u.sta.extra_ie_len;
+	} else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+		conf.ssid = sdata->u.ap.ssid;
+		conf.ssid_len = sdata->u.ap.ssid_len;
+		conf.generic_elem = sdata->u.ap.generic_elem;
+		conf.generic_elem_len = sdata->u.ap.generic_elem_len;
+		conf.beacon = beacon;
+		conf.beacon_control = control;
 	}
-	local->open_count++;
-
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
-		local->monitors++;
-		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-	} else
-		ieee80211_if_config(dev);
-
-	if (sdata->type == IEEE80211_IF_TYPE_STA &&
-	    !local->user_space_mlme)
-		netif_carrier_off(dev);
-	else
-		netif_carrier_on(dev);
-
-	netif_start_queue(dev);
-	return 0;
+	return local->ops->config_interface(local_to_hw(local),
+					   dev->ifindex, &conf);
 }
 
+int ieee80211_if_config(struct net_device *dev)
+{
+	return __ieee80211_if_config(dev, NULL, NULL);
+}
 
-static int ieee80211_stop(struct net_device *dev)
+int ieee80211_if_config_beacon(struct net_device *dev)
 {
-	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_tx_control control;
+	struct sk_buff *skb;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
-	    local->open_count > 1 &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		/* remove "soft monitor" interface */
-		local->open_count--;
-		local->monitors--;
-		if (!local->monitors)
-			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+	if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
 		return 0;
-	}
-
-	netif_stop_queue(dev);
-	ieee80211_if_shutdown(dev);
+	skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
+	if (!skb)
+		return -ENOMEM;
+	return __ieee80211_if_config(dev, skb, &control);
+}
 
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
-		local->monitors--;
-		if (!local->monitors)
-			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-	}
+int ieee80211_hw_config(struct ieee80211_local *local)
+{
+	struct ieee80211_hw_mode *mode;
+	struct ieee80211_channel *chan;
+	int ret = 0;
 
-	local->open_count--;
-	if (local->open_count == 0) {
-		if (netif_running(local->mdev))
-			dev_close(local->mdev);
-		if (local->apdev)
-			dev_close(local->apdev);
-		if (local->ops->stop)
-			local->ops->stop(local_to_hw(local));
-		tasklet_disable(&local->tx_pending_tasklet);
-		tasklet_disable(&local->tasklet);
+	if (local->sta_scanning) {
+		chan = local->scan_channel;
+		mode = local->scan_hw_mode;
+	} else {
+		chan = local->oper_channel;
+		mode = local->oper_hw_mode;
 	}
-	if (local->ops->remove_interface) {
-		struct ieee80211_if_init_conf conf;
 
-		conf.if_id = dev->ifindex;
-		conf.type = sdata->type;
-		conf.mac_addr = dev->dev_addr;
-		local->ops->remove_interface(local_to_hw(local), &conf);
-	}
+	local->hw.conf.channel = chan->chan;
+	local->hw.conf.channel_val = chan->val;
+	local->hw.conf.power_level = chan->power_level;
+	local->hw.conf.freq = chan->freq;
+	local->hw.conf.phymode = mode->mode;
+	local->hw.conf.antenna_max = chan->antenna_max;
+	local->hw.conf.chan = chan;
+	local->hw.conf.mode = mode;
 
-	ieee80211_start_hard_monitor(local);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
+	       "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
+	       local->hw.conf.phymode);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
-	return 0;
+	if (local->ops->config)
+		ret = local->ops->config(local_to_hw(local), &local->hw.conf);
+
+	return ret;
 }
 
 
-static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
+struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
+					       struct dev_mc_list *prev,
+					       void **ptr)
 {
-	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-	return ETH_ALEN;
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata = *ptr;
+	struct dev_mc_list *mc;
+
+	if (!prev) {
+		WARN_ON(sdata);
+		sdata = NULL;
+	}
+	if (!prev || !prev->next) {
+		if (sdata)
+			sdata = list_entry(sdata->list.next,
+					   struct ieee80211_sub_if_data, list);
+		else
+			sdata = list_entry(local->sub_if_list.next,
+					   struct ieee80211_sub_if_data, list);
+		if (&sdata->list != &local->sub_if_list)
+			mc = sdata->dev->mc_list;
+		else
+			mc = NULL;
+	} else
+		mc = prev->next;
+
+	*ptr = sdata;
+	return mc;
 }
+EXPORT_SYMBOL(ieee80211_get_mc_list_item);
 
 struct ieee80211_rate *
 ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
@@ -951,142 +1159,6 @@ ieee80211_get_rate(struct ieee80211_loca
 	return NULL;
 }
 
-static void
-ieee80211_fill_frame_info(struct ieee80211_local *local,
-			  struct ieee80211_frame_info *fi,
-			  struct ieee80211_rx_status *status)
-{
-	if (status) {
-		struct timespec ts;
-		struct ieee80211_rate *rate;
-
-		jiffies_to_timespec(jiffies, &ts);
-		fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
-					   ts.tv_nsec / 1000);
-		fi->mactime = cpu_to_be64(status->mactime);
-		switch (status->phymode) {
-		case MODE_IEEE80211A:
-			fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a);
-			break;
-		case MODE_IEEE80211B:
-			fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b);
-			break;
-		case MODE_IEEE80211G:
-			fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g);
-			break;
-		case MODE_ATHEROS_TURBO:
-			fi->phytype =
-				htonl(ieee80211_phytype_dsss_dot11_turbo);
-			break;
-		default:
-			fi->phytype = htonl(0xAAAAAAAA);
-			break;
-		}
-		fi->channel = htonl(status->channel);
-		rate = ieee80211_get_rate(local, status->phymode,
-					  status->rate);
-		if (rate) {
-			fi->datarate = htonl(rate->rate);
-			if (rate->flags & IEEE80211_RATE_PREAMBLE2) {
-				if (status->rate == rate->val)
-					fi->preamble = htonl(2); /* long */
-				else if (status->rate == rate->val2)
-					fi->preamble = htonl(1); /* short */
-			} else
-				fi->preamble = htonl(0);
-		} else {
-			fi->datarate = htonl(0);
-			fi->preamble = htonl(0);
-		}
-
-		fi->antenna = htonl(status->antenna);
-		fi->priority = htonl(0xffffffff); /* no clue */
-		fi->ssi_type = htonl(ieee80211_ssi_raw);
-		fi->ssi_signal = htonl(status->ssi);
-		fi->ssi_noise = 0x00000000;
-		fi->encoding = 0;
-	} else {
-		/* clear everything because we really don't know.
-		 * the msg_type field isn't present on monitor frames
-		 * so we don't know whether it will be present or not,
-		 * but it's ok to not clear it since it'll be assigned
-		 * anyway */
-		memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type));
-
-		fi->ssi_type = htonl(ieee80211_ssi_none);
-	}
-	fi->version = htonl(IEEE80211_FI_VERSION);
-	fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type));
-}
-
-/* this routine is actually not just for this, but also
- * for pushing fake 'management' frames into userspace.
- * it shall be replaced by a netlink-based system. */
-void
-ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
-		  struct ieee80211_rx_status *status, u32 msg_type)
-{
-	struct ieee80211_frame_info *fi;
-	const size_t hlen = sizeof(struct ieee80211_frame_info);
-	struct ieee80211_sub_if_data *sdata;
-
-	skb->dev = local->apdev;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev);
-
-	if (skb_headroom(skb) < hlen) {
-		I802_DEBUG_INC(local->rx_expand_skb_head);
-		if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
-			dev_kfree_skb(skb);
-			return;
-		}
-	}
-
-	fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
-
-	ieee80211_fill_frame_info(local, fi, status);
-	fi->msg_type = htonl(msg_type);
-
-	sdata->stats.rx_packets++;
-	sdata->stats.rx_bytes += skb->len;
-
-	skb_set_mac_header(skb, 0);
-	skb->ip_summed = CHECKSUM_UNNECESSARY;
-	skb->pkt_type = PACKET_OTHERHOST;
-	skb->protocol = htons(ETH_P_802_2);
-	memset(skb->cb, 0, sizeof(skb->cb));
-	netif_rx(skb);
-}
-
-int ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
-			   int radar, int radar_type)
-{
-	struct sk_buff *skb;
-	struct ieee80211_radar_info *msg;
-	struct ieee80211_local *local = hw_to_local(hw);
-
-	if (!local->apdev)
-		return 0;
-
-	skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
-			    sizeof(struct ieee80211_radar_info));
-
-	if (!skb)
-		return -ENOMEM;
-	skb_reserve(skb, sizeof(struct ieee80211_frame_info));
-
-	msg = (struct ieee80211_radar_info *)
-		skb_put(skb, sizeof(struct ieee80211_radar_info));
-	msg->channel = channel;
-	msg->radar = radar;
-	msg->radar_type = radar_type;
-
-	ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar);
-	return 0;
-}
-EXPORT_SYMBOL(ieee80211_radar_status);
-
-
 static void ieee80211_stat_refresh(unsigned long data)
 {
 	struct ieee80211_local *local = (struct ieee80211_local *) data;
@@ -1484,69 +1556,6 @@ void ieee80211_tx_status(struct ieee8021
 EXPORT_SYMBOL(ieee80211_tx_status);
 
 
-int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct sta_info *sta;
-
-	if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
-		return 0;
-
-	/* Create STA entry for the new peer */
-	sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
-	if (!sta)
-		return -ENOMEM;
-	sta_info_put(sta);
-
-	/* Remove STA entry for the old peer */
-	sta = sta_info_get(local, sdata->u.wds.remote_addr);
-	if (sta) {
-		sta_info_put(sta);
-		sta_info_free(sta, 0);
-	} else {
-		printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
-		       "peer " MAC_FMT "\n",
-		       dev->name, MAC_ARG(sdata->u.wds.remote_addr));
-	}
-
-	/* Update WDS link data */
-	memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
-
-	return 0;
-}
-
-/* Must not be called for mdev and apdev */
-void ieee80211_if_setup(struct net_device *dev)
-{
-	ether_setup(dev);
-	dev->hard_start_xmit = ieee80211_subif_start_xmit;
-	dev->wireless_handlers = &ieee80211_iw_handler_def;
-	dev->do_ioctl = ieee80211_ioctl;
-	dev->set_multicast_list = ieee80211_set_multicast_list;
-	dev->change_mtu = ieee80211_change_mtu;
-	dev->get_stats = ieee80211_get_stats;
-	dev->open = ieee80211_open;
-	dev->stop = ieee80211_stop;
-	dev->uninit = ieee80211_if_reinit;
-	dev->destructor = ieee80211_if_free;
-}
-
-void ieee80211_if_mgmt_setup(struct net_device *dev)
-{
-	ether_setup(dev);
-	dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
-	dev->change_mtu = ieee80211_change_mtu_apdev;
-	dev->get_stats = ieee80211_get_stats;
-	dev->open = ieee80211_mgmt_open;
-	dev->stop = ieee80211_mgmt_stop;
-	dev->type = ARPHRD_IEEE80211_PRISM;
-	dev->hard_header_parse = header_parse_80211;
-	dev->uninit = ieee80211_if_reinit;
-	dev->destructor = ieee80211_if_free;
-}
-
-
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 					const struct ieee80211_ops *ops)
 {

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 14/14] mac80211: introduce util.c
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (10 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 13/14] mac80211: reorder interface related functions Johannes Berg
@ 2007-06-21 22:16 ` Johannes Berg
  2007-06-22  9:09 ` [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
  2007-07-10 13:34 ` Jiri Benc
  13 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-21 22:16 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

Introduce a new file util.c and move a whole bunch of functions into it.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/mac80211/Makefile      |    1 
 net/mac80211/ieee80211.c   |  445 -----------------------------------------
 net/mac80211/ieee80211_i.h |   18 -
 net/mac80211/util.c        |  477 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 486 insertions(+), 455 deletions(-)

--- wireless-dev.orig/net/mac80211/Makefile	2007-06-22 00:09:02.118638003 +0200
+++ wireless-dev/net/mac80211/Makefile	2007-06-22 00:09:05.988638003 +0200
@@ -21,4 +21,5 @@ mac80211-objs := \
 	rx.o \
 	tx.o \
 	key.o \
+	util.o \
 	$(mac80211-objs-y)
--- wireless-dev.orig/net/mac80211/ieee80211.c	2007-06-22 00:03:32.868638003 +0200
+++ wireless-dev/net/mac80211/ieee80211.c	2007-06-22 00:10:47.518638003 +0200
@@ -34,23 +34,6 @@
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
-/* privid for wiphys to determine whether they belong to us or not */
-void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-const unsigned char rfc1042_header[] =
-	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-const unsigned char bridge_tunnel_header[] =
-	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-
-/* No encapsulation header if EtherType < 0x600 (=length) */
-static const unsigned char eapol_header[] =
-	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
-
-
 /*
  * For seeing transmitted packets on monitor interfaces
  * we have a radiotap header too.
@@ -667,354 +650,6 @@ int ieee80211_if_update_wds(struct net_d
 
 /* everything else */
 
-static int rate_list_match(const int *rate_list, int rate)
-{
-	int i;
-
-	if (!rate_list)
-		return 0;
-
-	for (i = 0; rate_list[i] >= 0; i++)
-		if (rate_list[i] == rate)
-			return 1;
-
-	return 0;
-}
-
-
-void ieee80211_prepare_rates(struct ieee80211_local *local,
-			     struct ieee80211_hw_mode *mode)
-{
-	int i;
-
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-
-		rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
-				 IEEE80211_RATE_BASIC);
-
-		if (local->supp_rates[mode->mode]) {
-			if (!rate_list_match(local->supp_rates[mode->mode],
-					     rate->rate))
-				continue;
-		}
-
-		rate->flags |= IEEE80211_RATE_SUPPORTED;
-
-		/* Use configured basic rate set if it is available. If not,
-		 * use defaults that are sane for most cases. */
-		if (local->basic_rates[mode->mode]) {
-			if (rate_list_match(local->basic_rates[mode->mode],
-					    rate->rate))
-				rate->flags |= IEEE80211_RATE_BASIC;
-		} else switch (mode->mode) {
-		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_IEEE80211B:
-			if (rate->rate == 10 || rate->rate == 20)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_ATHEROS_TURBO:
-			if (rate->rate == 120 || rate->rate == 240 ||
-			    rate->rate == 480)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		}
-
-		/* Set ERP and MANDATORY flags based on phymode */
-		switch (mode->mode) {
-		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case MODE_IEEE80211B:
-			if (rate->rate == 10)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case MODE_ATHEROS_TURBO:
-			break;
-		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110 ||
-			    rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		}
-		if (ieee80211_is_erp_rate(mode->mode, rate->rate))
-			rate->flags |= IEEE80211_RATE_ERP;
-	}
-}
-
-
-u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
-{
-	u16 fc;
-
-	if (len < 24)
-		return NULL;
-
-	fc = le16_to_cpu(hdr->frame_control);
-
-	switch (fc & IEEE80211_FCTL_FTYPE) {
-	case IEEE80211_FTYPE_DATA:
-		switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-		case IEEE80211_FCTL_TODS:
-			return hdr->addr1;
-		case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-			return NULL;
-		case IEEE80211_FCTL_FROMDS:
-			return hdr->addr2;
-		case 0:
-			return hdr->addr3;
-		}
-		break;
-	case IEEE80211_FTYPE_MGMT:
-		return hdr->addr3;
-	case IEEE80211_FTYPE_CTL:
-		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
-			return hdr->addr1;
-		else
-			return NULL;
-	}
-
-	return NULL;
-}
-
-int ieee80211_get_hdrlen(u16 fc)
-{
-	int hdrlen = 24;
-
-	switch (fc & IEEE80211_FCTL_FTYPE) {
-	case IEEE80211_FTYPE_DATA:
-		if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
-			hdrlen = 30; /* Addr4 */
-		/*
-		 * The QoS Control field is two bytes and its presence is
-		 * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
-		 * hdrlen if that bit is set.
-		 * This works by masking out the bit and shifting it to
-		 * bit position 1 so the result has the value 0 or 2.
-		 */
-		hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
-				>> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
-		break;
-	case IEEE80211_FTYPE_CTL:
-		/*
-		 * ACK and CTS are 10 bytes, all others 16. To see how
-		 * to get this condition consider
-		 *   subtype mask:   0b0000000011110000 (0x00F0)
-		 *   ACK subtype:    0b0000000011010000 (0x00D0)
-		 *   CTS subtype:    0b0000000011000000 (0x00C0)
-		 *   bits that matter:         ^^^      (0x00E0)
-		 *   value of those: 0b0000000011000000 (0x00C0)
-		 */
-		if ((fc & 0xE0) == 0xC0)
-			hdrlen = 10;
-		else
-			hdrlen = 16;
-		break;
-	}
-
-	return hdrlen;
-}
-EXPORT_SYMBOL(ieee80211_get_hdrlen);
-
-int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
-{
-	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
-	int hdrlen;
-
-	if (unlikely(skb->len < 10))
-		return 0;
-	hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
-	if (unlikely(hdrlen > skb->len))
-		return 0;
-	return hdrlen;
-}
-EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
-
-
-int ieee80211_is_eapol(const struct sk_buff *skb)
-{
-	const struct ieee80211_hdr *hdr;
-	u16 fc;
-	int hdrlen;
-
-	if (unlikely(skb->len < 10))
-		return 0;
-
-	hdr = (const struct ieee80211_hdr *) skb->data;
-	fc = le16_to_cpu(hdr->frame_control);
-
-	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-		return 0;
-
-	hdrlen = ieee80211_get_hdrlen(fc);
-
-	if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
-		     memcmp(skb->data + hdrlen, eapol_header,
-			    sizeof(eapol_header)) == 0))
-		return 1;
-
-	return 0;
-}
-
-
-void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
-{
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-
-	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-	if (tx->u.tx.extra_frag) {
-		struct ieee80211_hdr *fhdr;
-		int i;
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-			fhdr = (struct ieee80211_hdr *)
-				tx->u.tx.extra_frag[i]->data;
-			fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-		}
-	}
-}
-
-
-int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
-			     int rate, int erp, int short_preamble)
-{
-	int dur;
-
-	/* calculate duration (in microseconds, rounded up to next higher
-	 * integer if it includes a fractional microsecond) to send frame of
-	 * len bytes (does not include FCS) at the given rate. Duration will
-	 * also include SIFS.
-	 *
-	 * rate is in 100 kbps, so divident is multiplied by 10 in the
-	 * DIV_ROUND_UP() operations.
-	 */
-
-	if (local->hw.conf.phymode == MODE_IEEE80211A || erp ||
-	    local->hw.conf.phymode == MODE_ATHEROS_TURBO) {
-		/*
-		 * OFDM:
-		 *
-		 * N_DBPS = DATARATE x 4
-		 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
-		 *	(16 = SIGNAL time, 6 = tail bits)
-		 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
-		 *
-		 * T_SYM = 4 usec
-		 * 802.11a - 17.5.2: aSIFSTime = 16 usec
-		 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
-		 *	signal ext = 6 usec
-		 */
-		/* FIX: Atheros Turbo may have different (shorter) duration? */
-		dur = 16; /* SIFS + signal ext */
-		dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
-		dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
-		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
-					4 * rate); /* T_SYM x N_SYM */
-	} else {
-		/*
-		 * 802.11b or 802.11g with 802.11b compatibility:
-		 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
-		 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
-		 *
-		 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
-		 * aSIFSTime = 10 usec
-		 * aPreambleLength = 144 usec or 72 usec with short preamble
-		 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
-		 */
-		dur = 10; /* aSIFSTime = 10 usec */
-		dur += short_preamble ? (72 + 24) : (144 + 48);
-
-		dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
-	}
-
-	return dur;
-}
-
-
-/* Exported duration function for driver use */
-__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
-					size_t frame_len, int rate)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	u16 dur;
-	int erp;
-
-	erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
-	dur = ieee80211_frame_duration(local, frame_len, rate,
-				       erp, local->short_preamble);
-
-	return cpu_to_le16(dur);
-}
-EXPORT_SYMBOL(ieee80211_generic_frame_duration);
-
-
-__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
-			      size_t frame_len,
-			      const struct ieee80211_tx_control *frame_txctl)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_rate *rate;
-	int short_preamble = local->short_preamble;
-	int erp;
-	u16 dur;
-
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
-
-	/* CTS duration */
-	dur = ieee80211_frame_duration(local, 10, rate->rate,
-				       erp, short_preamble);
-	/* Data frame duration */
-	dur += ieee80211_frame_duration(local, frame_len, rate->rate,
-					erp, short_preamble);
-	/* ACK duration */
-	dur += ieee80211_frame_duration(local, 10, rate->rate,
-					erp, short_preamble);
-
-	return cpu_to_le16(dur);
-}
-EXPORT_SYMBOL(ieee80211_rts_duration);
-
-
-__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
-				    size_t frame_len,
-				    const struct ieee80211_tx_control *frame_txctl)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_rate *rate;
-	int short_preamble = local->short_preamble;
-	int erp;
-	u16 dur;
-
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
-
-	/* Data frame duration */
-	dur = ieee80211_frame_duration(local, frame_len, rate->rate,
-				       erp, short_preamble);
-	if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
-		/* ACK duration */
-		dur += ieee80211_frame_duration(local, 10, rate->rate,
-						erp, short_preamble);
-	}
-
-	return cpu_to_le16(dur);
-}
-EXPORT_SYMBOL(ieee80211_ctstoself_duration);
-
-
 static int __ieee80211_if_config(struct net_device *dev,
 				 struct sk_buff *beacon,
 				 struct ieee80211_tx_control *control)
@@ -1138,27 +773,6 @@ struct dev_mc_list *ieee80211_get_mc_lis
 }
 EXPORT_SYMBOL(ieee80211_get_mc_list_item);
 
-struct ieee80211_rate *
-ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
-{
-	struct ieee80211_hw_mode *mode;
-	int r;
-
-	list_for_each_entry(mode, &local->modes_list, list) {
-		if (mode->mode != phymode)
-			continue;
-		for (r = 0; r < mode->num_rates; r++) {
-			struct ieee80211_rate *rate = &mode->rates[r];
-			if (rate->val == hw_rate ||
-			    (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
-			     rate->val2 == hw_rate))
-				return rate;
-		}
-	}
-
-	return NULL;
-}
-
 static void ieee80211_stat_refresh(unsigned long data)
 {
 	struct ieee80211_local *local = (struct ieee80211_local *) data;
@@ -1878,65 +1492,6 @@ void ieee80211_free_hw(struct ieee80211_
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
 
-void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-
-	if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
-			       &local->state[queue])) {
-		if (test_bit(IEEE80211_LINK_STATE_PENDING,
-			     &local->state[queue]))
-			tasklet_schedule(&local->tx_pending_tasklet);
-		else
-			if (!ieee80211_qdisc_installed(local->mdev)) {
-				if (queue == 0)
-					netif_wake_queue(local->mdev);
-			} else
-				__netif_schedule(local->mdev);
-	}
-}
-EXPORT_SYMBOL(ieee80211_wake_queue);
-
-void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-
-	if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
-		netif_stop_queue(local->mdev);
-	set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
-}
-EXPORT_SYMBOL(ieee80211_stop_queue);
-
-void ieee80211_start_queues(struct ieee80211_hw *hw)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	int i;
-
-	for (i = 0; i < local->hw.queues; i++)
-		clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
-	if (!ieee80211_qdisc_installed(local->mdev))
-		netif_start_queue(local->mdev);
-}
-EXPORT_SYMBOL(ieee80211_start_queues);
-
-void ieee80211_stop_queues(struct ieee80211_hw *hw)
-{
-	int i;
-
-	for (i = 0; i < hw->queues; i++)
-		ieee80211_stop_queue(hw, i);
-}
-EXPORT_SYMBOL(ieee80211_stop_queues);
-
-void ieee80211_wake_queues(struct ieee80211_hw *hw)
-{
-	int i;
-
-	for (i = 0; i < hw->queues; i++)
-		ieee80211_wake_queue(hw, i);
-}
-EXPORT_SYMBOL(ieee80211_wake_queues);
-
 struct net_device_stats *ieee80211_dev_stats(struct net_device *dev)
 {
 	struct ieee80211_sub_if_data *sdata;
--- wireless-dev.orig/net/mac80211/ieee80211_i.h	2007-06-22 00:07:17.748638003 +0200
+++ wireless-dev/net/mac80211/ieee80211_i.h	2007-06-22 00:08:05.368638003 +0200
@@ -809,14 +809,6 @@ struct ieee80211_rate *ieee80211_get_rat
 void ieee80211_key_threshold_notify(struct net_device *dev,
 				    struct ieee80211_key *key,
 				    struct sta_info *sta);
-u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
-int ieee80211_is_eapol(const struct sk_buff *skb);
-
-extern const unsigned char rfc1042_header[6];
-extern const unsigned char bridge_tunnel_header[6];
-
-int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
-			     int rate, int erp, int short_preamble);
 /* ieee80211_ioctl.c */
 int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 extern const struct iw_handler_def ieee80211_iw_handler_def;
@@ -936,7 +928,13 @@ struct ieee80211_key *ieee80211_key_allo
 					  int idx, size_t key_len, gfp_t flags);
 void ieee80211_key_free(struct ieee80211_key *key);
 
-/* for wiphy privid */
-extern void *mac80211_wiphy_privid;
+/* utility functions/constants */
+extern void *mac80211_wiphy_privid; /* for wiphy privid */
+extern const unsigned char rfc1042_header[6];
+extern const unsigned char bridge_tunnel_header[6];
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len);
+int ieee80211_is_eapol(const struct sk_buff *skb);
+int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+			     int rate, int erp, int short_preamble);
 
 #endif /* IEEE80211_I_H */
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-dev/net/mac80211/util.c	2007-06-22 00:10:39.918638003 +0200
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * utilities for mac80211
+ */
+
+#include <net/mac80211.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitmap.h>
+#include <net/cfg80211.h>
+
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "wme.h"
+
+/* privid for wiphys to determine whether they belong to us or not */
+void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+const unsigned char rfc1042_header[] =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+const unsigned char bridge_tunnel_header[] =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+
+/* No encapsulation header if EtherType < 0x600 (=length) */
+static const unsigned char eapol_header[] =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
+
+
+
+static int rate_list_match(const int *rate_list, int rate)
+{
+	int i;
+
+	if (!rate_list)
+		return 0;
+
+	for (i = 0; rate_list[i] >= 0; i++)
+		if (rate_list[i] == rate)
+			return 1;
+
+	return 0;
+}
+
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+			     struct ieee80211_hw_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *rate = &mode->rates[i];
+
+		rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
+				 IEEE80211_RATE_BASIC);
+
+		if (local->supp_rates[mode->mode]) {
+			if (!rate_list_match(local->supp_rates[mode->mode],
+					     rate->rate))
+				continue;
+		}
+
+		rate->flags |= IEEE80211_RATE_SUPPORTED;
+
+		/* Use configured basic rate set if it is available. If not,
+		 * use defaults that are sane for most cases. */
+		if (local->basic_rates[mode->mode]) {
+			if (rate_list_match(local->basic_rates[mode->mode],
+					    rate->rate))
+				rate->flags |= IEEE80211_RATE_BASIC;
+		} else switch (mode->mode) {
+		case MODE_IEEE80211A:
+			if (rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_IEEE80211B:
+			if (rate->rate == 10 || rate->rate == 20)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_ATHEROS_TURBO:
+			if (rate->rate == 120 || rate->rate == 240 ||
+			    rate->rate == 480)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_IEEE80211G:
+			if (rate->rate == 10 || rate->rate == 20 ||
+			    rate->rate == 55 || rate->rate == 110)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		}
+
+		/* Set ERP and MANDATORY flags based on phymode */
+		switch (mode->mode) {
+		case MODE_IEEE80211A:
+			if (rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		case MODE_IEEE80211B:
+			if (rate->rate == 10)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		case MODE_ATHEROS_TURBO:
+			break;
+		case MODE_IEEE80211G:
+			if (rate->rate == 10 || rate->rate == 20 ||
+			    rate->rate == 55 || rate->rate == 110 ||
+			    rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		}
+		if (ieee80211_is_erp_rate(mode->mode, rate->rate))
+			rate->flags |= IEEE80211_RATE_ERP;
+	}
+}
+
+
+u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc;
+
+	if (len < 24)
+		return NULL;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+		case IEEE80211_FCTL_TODS:
+			return hdr->addr1;
+		case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+			return NULL;
+		case IEEE80211_FCTL_FROMDS:
+			return hdr->addr2;
+		case 0:
+			return hdr->addr3;
+		}
+		break;
+	case IEEE80211_FTYPE_MGMT:
+		return hdr->addr3;
+	case IEEE80211_FTYPE_CTL:
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
+			return hdr->addr1;
+		else
+			return NULL;
+	}
+
+	return NULL;
+}
+
+int ieee80211_get_hdrlen(u16 fc)
+{
+	int hdrlen = 24;
+
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+			hdrlen = 30; /* Addr4 */
+		/*
+		 * The QoS Control field is two bytes and its presence is
+		 * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
+		 * hdrlen if that bit is set.
+		 * This works by masking out the bit and shifting it to
+		 * bit position 1 so the result has the value 0 or 2.
+		 */
+		hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
+				>> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
+		break;
+	case IEEE80211_FTYPE_CTL:
+		/*
+		 * ACK and CTS are 10 bytes, all others 16. To see how
+		 * to get this condition consider
+		 *   subtype mask:   0b0000000011110000 (0x00F0)
+		 *   ACK subtype:    0b0000000011010000 (0x00D0)
+		 *   CTS subtype:    0b0000000011000000 (0x00C0)
+		 *   bits that matter:         ^^^      (0x00E0)
+		 *   value of those: 0b0000000011000000 (0x00C0)
+		 */
+		if ((fc & 0xE0) == 0xC0)
+			hdrlen = 10;
+		else
+			hdrlen = 16;
+		break;
+	}
+
+	return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen);
+
+
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
+	int hdrlen;
+
+	if (unlikely(skb->len < 10))
+		return 0;
+	hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+	if (unlikely(hdrlen > skb->len))
+		return 0;
+	return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+
+
+int ieee80211_is_eapol(const struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr;
+	u16 fc;
+	int hdrlen;
+
+	if (unlikely(skb->len < 10))
+		return 0;
+
+	hdr = (const struct ieee80211_hdr *) skb->data;
+	fc = le16_to_cpu(hdr->frame_control);
+
+	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+		return 0;
+
+	hdrlen = ieee80211_get_hdrlen(fc);
+
+	if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
+		     memcmp(skb->data + hdrlen, eapol_header,
+			    sizeof(eapol_header)) == 0))
+		return 1;
+
+	return 0;
+}
+
+
+void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+
+	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	if (tx->u.tx.extra_frag) {
+		struct ieee80211_hdr *fhdr;
+		int i;
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			fhdr = (struct ieee80211_hdr *)
+				tx->u.tx.extra_frag[i]->data;
+			fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		}
+	}
+}
+
+
+int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+			     int rate, int erp, int short_preamble)
+{
+	int dur;
+
+	/* calculate duration (in microseconds, rounded up to next higher
+	 * integer if it includes a fractional microsecond) to send frame of
+	 * len bytes (does not include FCS) at the given rate. Duration will
+	 * also include SIFS.
+	 *
+	 * rate is in 100 kbps, so divident is multiplied by 10 in the
+	 * DIV_ROUND_UP() operations.
+	 */
+
+	if (local->hw.conf.phymode == MODE_IEEE80211A || erp ||
+	    local->hw.conf.phymode == MODE_ATHEROS_TURBO) {
+		/*
+		 * OFDM:
+		 *
+		 * N_DBPS = DATARATE x 4
+		 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
+		 *	(16 = SIGNAL time, 6 = tail bits)
+		 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
+		 *
+		 * T_SYM = 4 usec
+		 * 802.11a - 17.5.2: aSIFSTime = 16 usec
+		 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
+		 *	signal ext = 6 usec
+		 */
+		/* FIX: Atheros Turbo may have different (shorter) duration? */
+		dur = 16; /* SIFS + signal ext */
+		dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
+		dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
+		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
+					4 * rate); /* T_SYM x N_SYM */
+	} else {
+		/*
+		 * 802.11b or 802.11g with 802.11b compatibility:
+		 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
+		 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
+		 *
+		 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
+		 * aSIFSTime = 10 usec
+		 * aPreambleLength = 144 usec or 72 usec with short preamble
+		 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
+		 */
+		dur = 10; /* aSIFSTime = 10 usec */
+		dur += short_preamble ? (72 + 24) : (144 + 48);
+
+		dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
+	}
+
+	return dur;
+}
+
+
+/* Exported duration function for driver use */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+					size_t frame_len, int rate)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	u16 dur;
+	int erp;
+
+	erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
+	dur = ieee80211_frame_duration(local, frame_len, rate,
+				       erp, local->short_preamble);
+
+	return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_generic_frame_duration);
+
+
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+			      size_t frame_len,
+			      const struct ieee80211_tx_control *frame_txctl)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rate *rate;
+	int short_preamble = local->short_preamble;
+	int erp;
+	u16 dur;
+
+	rate = frame_txctl->rts_rate;
+	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+	/* CTS duration */
+	dur = ieee80211_frame_duration(local, 10, rate->rate,
+				       erp, short_preamble);
+	/* Data frame duration */
+	dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+					erp, short_preamble);
+	/* ACK duration */
+	dur += ieee80211_frame_duration(local, 10, rate->rate,
+					erp, short_preamble);
+
+	return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_rts_duration);
+
+
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+				    size_t frame_len,
+				    const struct ieee80211_tx_control *frame_txctl)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rate *rate;
+	int short_preamble = local->short_preamble;
+	int erp;
+	u16 dur;
+
+	rate = frame_txctl->rts_rate;
+	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+	/* Data frame duration */
+	dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+				       erp, short_preamble);
+	if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+		/* ACK duration */
+		dur += ieee80211_frame_duration(local, 10, rate->rate,
+						erp, short_preamble);
+	}
+
+	return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_duration);
+
+
+struct ieee80211_rate *
+ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
+{
+	struct ieee80211_hw_mode *mode;
+	int r;
+
+	list_for_each_entry(mode, &local->modes_list, list) {
+		if (mode->mode != phymode)
+			continue;
+		for (r = 0; r < mode->num_rates; r++) {
+			struct ieee80211_rate *rate = &mode->rates[r];
+			if (rate->val == hw_rate ||
+			    (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
+			     rate->val2 == hw_rate))
+				return rate;
+		}
+	}
+
+	return NULL;
+}
+
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
+			       &local->state[queue])) {
+		if (test_bit(IEEE80211_LINK_STATE_PENDING,
+			     &local->state[queue]))
+			tasklet_schedule(&local->tx_pending_tasklet);
+		else
+			if (!ieee80211_qdisc_installed(local->mdev)) {
+				if (queue == 0)
+					netif_wake_queue(local->mdev);
+			} else
+				__netif_schedule(local->mdev);
+	}
+}
+EXPORT_SYMBOL(ieee80211_wake_queue);
+
+
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
+		netif_stop_queue(local->mdev);
+	set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+EXPORT_SYMBOL(ieee80211_stop_queue);
+
+
+void ieee80211_start_queues(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	int i;
+
+	for (i = 0; i < local->hw.queues; i++)
+		clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
+	if (!ieee80211_qdisc_installed(local->mdev))
+		netif_start_queue(local->mdev);
+}
+EXPORT_SYMBOL(ieee80211_start_queues);
+
+
+void ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+	int i;
+
+	for (i = 0; i < hw->queues; i++)
+		ieee80211_stop_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_stop_queues);
+
+
+void ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+	int i;
+
+	for (i = 0; i < hw->queues; i++)
+		ieee80211_wake_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_wake_queues);

-- 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (11 preceding siblings ...)
  2007-06-21 22:16 ` [PATCH 14/14] mac80211: introduce util.c Johannes Berg
@ 2007-06-22  9:09 ` Johannes Berg
  2007-06-28 10:59   ` Johannes Berg
  2007-07-10 13:34 ` Jiri Benc
  13 siblings, 1 reply; 26+ messages in thread
From: Johannes Berg @ 2007-06-22  9:09 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 253 bytes --]

Apparently 1 and 8 were too large:

(1)
http://johannes.sipsolutions.net/patches/kernel/all/2007-06-22-09:08/033-split-rx.patch

(8)
http://johannes.sipsolutions.net/patches/kernel/all/2007-06-22-09:08/040-split-out-tx-handlers.patch

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-06-22  9:09 ` [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
@ 2007-06-28 10:59   ` Johannes Berg
  0 siblings, 0 replies; 26+ messages in thread
From: Johannes Berg @ 2007-06-28 10:59 UTC (permalink / raw)
  To: John Linville; +Cc: Jiri Benc, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 597 bytes --]

On Fri, 2007-06-22 at 11:09 +0200, Johannes Berg wrote:
> Apparently 1 and 8 were too large:
> 
> (1)
> http://johannes.sipsolutions.net/patches/kernel/all/2007-06-22-09:08/033-split-rx.patch
> 
> (8)
> http://johannes.sipsolutions.net/patches/kernel/all/2007-06-22-09:08/040-split-out-tx-handlers.patch

I should have mentioned that these also reorder the rx handlers to be in
the same order as they're invoked in which makes reading that code a lot
easier since you can just read it top-down without worrying about
jumping around to find the correct order all the time.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
                   ` (12 preceding siblings ...)
  2007-06-22  9:09 ` [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
@ 2007-07-10 13:34 ` Jiri Benc
  2007-07-10 13:50   ` Johannes Berg
  13 siblings, 1 reply; 26+ messages in thread
From: Jiri Benc @ 2007-07-10 13:34 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, linux-wireless

On Fri, 22 Jun 2007 00:16:03 +0200, Johannes Berg wrote:
> ieee80211.c is just too large to be maintainable. This patch series
> splits it up into a few smaller files; it also has a few tiny
> buglet-fixes.

I agree. And I like these patches, they make sense.

But: It would make putting changes currently in wireless-dev to upstream a
nightmare. I wouldn't be able to take patches in the form they were
committed anymore and would need to heavily modify them.

Sorry, NAK for now. Let's do that after mac80211 is completely upstream.

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-10 13:34 ` Jiri Benc
@ 2007-07-10 13:50   ` Johannes Berg
  2007-07-10 14:29     ` Jiri Benc
  0 siblings, 1 reply; 26+ messages in thread
From: Johannes Berg @ 2007-07-10 13:50 UTC (permalink / raw)
  To: Jiri Benc; +Cc: John Linville, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 336 bytes --]

On Tue, 2007-07-10 at 15:34 +0200, Jiri Benc wrote:

> But: It would make putting changes currently in wireless-dev to upstream a
> nightmare. I wouldn't be able to take patches in the form they were
> committed anymore and would need to heavily modify them.

Why? We could just mirror these changes to upstream too.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-10 13:50   ` Johannes Berg
@ 2007-07-10 14:29     ` Jiri Benc
  2007-07-10 14:51       ` Johannes Berg
  0 siblings, 1 reply; 26+ messages in thread
From: Jiri Benc @ 2007-07-10 14:29 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John Linville, linux-wireless

On Tue, 10 Jul 2007 15:50:39 +0200, Johannes Berg wrote:
> On Tue, 2007-07-10 at 15:34 +0200, Jiri Benc wrote:
> 
> > But: It would make putting changes currently in wireless-dev to upstream a
> > nightmare. I wouldn't be able to take patches in the form they were
> > committed anymore and would need to heavily modify them.
> 
> Why? We could just mirror these changes to upstream too.

Unfortunately, content of upstream ieee80211.c is different - it doesn't
contain .11n and wmm pieces, etc.

But even if it can be applied upstream, it doesn't solve anything. Imagine
a patch which was merged into wireless-dev before this restructuring and
which is not upstream. Merging it upstream would mean taking the patch from
wireless-dev git and manually modifying it to fit a new structure. And we
have a bunch of such patches which should go to 2.6.24 (yes, I really
mean .24). Perhaps I'm lazy, but I'd like to avoid that. It's going to be a
lot of unpleasant work even without this...

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-10 14:29     ` Jiri Benc
@ 2007-07-10 14:51       ` Johannes Berg
  2007-07-10 17:12         ` John W. Linville
  2007-07-11 16:34         ` jketreno
  0 siblings, 2 replies; 26+ messages in thread
From: Johannes Berg @ 2007-07-10 14:51 UTC (permalink / raw)
  To: Jiri Benc; +Cc: John Linville, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 645 bytes --]

On Tue, 2007-07-10 at 16:29 +0200, Jiri Benc wrote:

> But even if it can be applied upstream, it doesn't solve anything. Imagine
> a patch which was merged into wireless-dev before this restructuring and
> which is not upstream. Merging it upstream would mean taking the patch from
> wireless-dev git and manually modifying it to fit a new structure. And we
> have a bunch of such patches which should go to 2.6.24 (yes, I really
> mean .24). Perhaps I'm lazy, but I'd like to avoid that. It's going to be a
> lot of unpleasant work even without this...

Which all goes to say that pushing mac80211 for .22 was too fast.

joahnnes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-10 14:51       ` Johannes Berg
@ 2007-07-10 17:12         ` John W. Linville
  2007-07-10 18:35           ` Johannes Berg
  2007-07-11 16:34         ` jketreno
  1 sibling, 1 reply; 26+ messages in thread
From: John W. Linville @ 2007-07-10 17:12 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Jiri Benc, linux-wireless

On Tue, Jul 10, 2007 at 04:51:18PM +0200, Johannes Berg wrote:
> On Tue, 2007-07-10 at 16:29 +0200, Jiri Benc wrote:

> > which is not upstream. Merging it upstream would mean taking the patch from
> > wireless-dev git and manually modifying it to fit a new structure. And we
> > have a bunch of such patches which should go to 2.6.24 (yes, I really
> > mean .24). Perhaps I'm lazy, but I'd like to avoid that. It's going to be a
> > lot of unpleasant work even without this...
> 
> Which all goes to say that pushing mac80211 for .22 was too fast.

Hmmmm...maybe.  But, what would have been the perfect trigger to
merge it?  At least now we have less bits out-of-stream and have to
do less API-chasing with every new kernel.

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-10 17:12         ` John W. Linville
@ 2007-07-10 18:35           ` Johannes Berg
  2007-07-11 20:20             ` Christoph Hellwig
  0 siblings, 1 reply; 26+ messages in thread
From: Johannes Berg @ 2007-07-10 18:35 UTC (permalink / raw)
  To: John W. Linville; +Cc: Jiri Benc, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 1358 bytes --]

On Tue, 2007-07-10 at 13:12 -0400, John W. Linville wrote:

> > > which is not upstream. Merging it upstream would mean taking the patch from
> > > wireless-dev git and manually modifying it to fit a new structure. And we
> > > have a bunch of such patches which should go to 2.6.24 (yes, I really
> > > mean .24). Perhaps I'm lazy, but I'd like to avoid that. It's going to be a
> > > lot of unpleasant work even without this...

> Hmmmm...maybe.  But, what would have been the perfect trigger to
> merge it?  At least now we have less bits out-of-stream and have to
> do less API-chasing with every new kernel.

Dunno. I guess I didn't expect Jiri to block any patches based on the
fact that we have two trees now.

I don't really see the big problem anyhow. As long as we don't want any
patches in upstream that depend on the refactoring we can delay pushing
the refactoring upstream. Once we do get patches we can decide to either
make two versions of them or at some point push the refactoring upstream
as well; problems will only arise if we delay too much pushing patches
upstream that are before the refactoring, those would need to be
rediffed.

Oh well. Do what you feel is easiest. This is the second or third time
I've been burnt with significant mac80211 cleanups so I guess I'll just
learn my lesson here.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-10 14:51       ` Johannes Berg
  2007-07-10 17:12         ` John W. Linville
@ 2007-07-11 16:34         ` jketreno
  2007-07-11 20:06           ` Joerg Mayer
  1 sibling, 1 reply; 26+ messages in thread
From: jketreno @ 2007-07-11 16:34 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Jiri Benc, John Linville, linux-wireless

Johannes Berg wrote:
> On Tue, 2007-07-10 at 16:29 +0200, Jiri Benc wrote:
> 
>> But even if it can be applied upstream, it doesn't solve anything. Imagine
>> a patch which was merged into wireless-dev before this restructuring and
>> which is not upstream. Merging it upstream would mean taking the patch from
>> wireless-dev git and manually modifying it to fit a new structure. And we
>> have a bunch of such patches which should go to 2.6.24 (yes, I really
>> mean .24). Perhaps I'm lazy, but I'd like to avoid that. It's going to be a
>> lot of unpleasant work even without this...
> 
> Which all goes to say that pushing mac80211 for .22 was too fast.

Definitely not too fast.  

The fact that people are using mac80211 from Linus' kernel tip is *GREAT*.  
We have a lot of users now that can pull Linus' tree and use iwlwifi and 
they no longer have to figure out how to patch a kernel, or pull from 
wireless-dev.

The fact that people are working on making patches against mac80211  is 
exactly what mac80211 needs.  By pushing at least some bits out we now 
have a larger audience testing, contributing, and working on making 
mac80211 better.

James

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-11 16:34         ` jketreno
@ 2007-07-11 20:06           ` Joerg Mayer
  0 siblings, 0 replies; 26+ messages in thread
From: Joerg Mayer @ 2007-07-11 20:06 UTC (permalink / raw)
  To: jketreno; +Cc: Johannes Berg, Jiri Benc, John Linville, linux-wireless

On Wed, Jul 11, 2007 at 09:34:50AM -0700, jketreno wrote:
> Johannes Berg wrote:
...
> >Which all goes to say that pushing mac80211 for .22 was too fast.
> 
> Definitely not too fast.  
> 
> The fact that people are using mac80211 from Linus' kernel tip is *GREAT*.  
> We have a lot of users now that can pull Linus' tree and use iwlwifi and 
> they no longer have to figure out how to patch a kernel, or pull from 
> wireless-dev.
...

Which reminds me: Will the driver make it into .23?

 ciao
    Joerg

-- 
Joerg Mayer                                           <jmayer@loplof.de>
We are stuck with technology when what we really want is just stuff that
works. Some say that should read Microsoft instead of technology.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-10 18:35           ` Johannes Berg
@ 2007-07-11 20:20             ` Christoph Hellwig
  2007-07-17 13:54               ` Luis R. Rodriguez
  0 siblings, 1 reply; 26+ messages in thread
From: Christoph Hellwig @ 2007-07-11 20:20 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John W. Linville, Jiri Benc, linux-wireless

On Tue, Jul 10, 2007 at 08:35:00PM +0200, Johannes Berg wrote:
> I don't really see the big problem anyhow. As long as we don't want any
> patches in upstream that depend on the refactoring we can delay pushing
> the refactoring upstream. Once we do get patches we can decide to either
> make two versions of them or at some point push the refactoring upstream
> as well; problems will only arise if we delay too much pushing patches
> upstream that are before the refactoring, those would need to be
> rediffed.

The normal Linux aproach is to push the refactoring as soon as possible.
That way the other changes have to be rebased once and than you're done
with it.  If you keep the big refactoring in some staging tree porting
things forth and back will be an endless pain.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-11 20:20             ` Christoph Hellwig
@ 2007-07-17 13:54               ` Luis R. Rodriguez
  2007-07-17 13:57                 ` Luis R. Rodriguez
  0 siblings, 1 reply; 26+ messages in thread
From: Luis R. Rodriguez @ 2007-07-17 13:54 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Johannes Berg, John W. Linville, Jiri Benc, linux-wireless

On 7/11/07, Christoph Hellwig <hch@infradead.org> wrote:
> On Tue, Jul 10, 2007 at 08:35:00PM +0200, Johannes Berg wrote:
> > I don't really see the big problem anyhow. As long as we don't want any
> > patches in upstream that depend on the refactoring we can delay pushing
> > the refactoring upstream. Once we do get patches we can decide to either
> > make two versions of them or at some point push the refactoring upstream
> > as well; problems will only arise if we delay too much pushing patches
> > upstream that are before the refactoring, those would need to be
> > rediffed.
>
> The normal Linux aproach is to push the refactoring as soon as possible.
> That way the other changes have to be rebased once and than you're done
> with it.  If you keep the big refactoring in some staging tree porting
> things forth and back will be an endless pain.

This is true but the idea is to try to merge wireless-dev into
wireless-2.6 ASAP. We shouldn't stop wireless-dev tree changes as that
is what we need to help with development. I can only see this helping
us down the road. Jiri -- are you sure? :)

  Luis

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 00/14] major mac80211 restructuring/cleanups
  2007-07-17 13:54               ` Luis R. Rodriguez
@ 2007-07-17 13:57                 ` Luis R. Rodriguez
  0 siblings, 0 replies; 26+ messages in thread
From: Luis R. Rodriguez @ 2007-07-17 13:57 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Johannes Berg, John W. Linville, Jiri Benc, linux-wireless

On 7/17/07, Luis R. Rodriguez <mcgrof@gmail.com> wrote:
> On 7/11/07, Christoph Hellwig <hch@infradead.org> wrote:
> > On Tue, Jul 10, 2007 at 08:35:00PM +0200, Johannes Berg wrote:
> > > I don't really see the big problem anyhow. As long as we don't want any
> > > patches in upstream that depend on the refactoring we can delay pushing
> > > the refactoring upstream. Once we do get patches we can decide to either
> > > make two versions of them or at some point push the refactoring upstream
> > > as well; problems will only arise if we delay too much pushing patches
> > > upstream that are before the refactoring, those would need to be
> > > rediffed.
> >
> > The normal Linux aproach is to push the refactoring as soon as possible.
> > That way the other changes have to be rebased once and than you're done
> > with it.  If you keep the big refactoring in some staging tree porting
> > things forth and back will be an endless pain.
>
> This is true but the idea is to try to merge wireless-dev into
> wireless-2.6 ASAP. We shouldn't stop wireless-dev tree changes as that
> is what we need to help with development. I can only see this helping
> us down the road. Jiri -- are you sure? :)

Nevermind... Johannes' patches won't apply anymore, except for the
ones he pinged about for recently...

  Luis

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2007-07-17 13:57 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-21 22:16 [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
2007-06-21 22:16 ` [PATCH 02/14] mac80211: move QoS rx handlers into rx.c Johannes Berg
2007-06-21 22:16 ` [PATCH 03/14] mac80211: rx cleanups (1) Johannes Berg
2007-06-21 22:16 ` [PATCH 04/14] mac80211: split ieee80211_rx_h_check handler Johannes Berg
2007-06-21 22:16 ` [PATCH 05/14] mac80211: split up __ieee80211_rx Johannes Berg
2007-06-21 22:16 ` [PATCH 06/14] mac80211: fix bug for per-sta stats Johannes Berg
2007-06-21 22:16 ` [PATCH 07/14] mac80211: rx cleanups (2) Johannes Berg
2007-06-21 22:16 ` [PATCH 09/14] mac80211: remove some unnecessary includes Johannes Berg
2007-06-21 22:16 ` [PATCH 10/14] mac80211: split out some key functions from ieee80211.c Johannes Berg
2007-06-21 22:16 ` [PATCH 11/14] mac80211: regdomain.c needs to include ieee80211_i.h Johannes Berg
2007-06-21 22:16 ` [PATCH 12/14] mac80211: move some rate control functions out of ieee80211.c Johannes Berg
2007-06-21 22:16 ` [PATCH 13/14] mac80211: reorder interface related functions Johannes Berg
2007-06-21 22:16 ` [PATCH 14/14] mac80211: introduce util.c Johannes Berg
2007-06-22  9:09 ` [PATCH 00/14] major mac80211 restructuring/cleanups Johannes Berg
2007-06-28 10:59   ` Johannes Berg
2007-07-10 13:34 ` Jiri Benc
2007-07-10 13:50   ` Johannes Berg
2007-07-10 14:29     ` Jiri Benc
2007-07-10 14:51       ` Johannes Berg
2007-07-10 17:12         ` John W. Linville
2007-07-10 18:35           ` Johannes Berg
2007-07-11 20:20             ` Christoph Hellwig
2007-07-17 13:54               ` Luis R. Rodriguez
2007-07-17 13:57                 ` Luis R. Rodriguez
2007-07-11 16:34         ` jketreno
2007-07-11 20:06           ` Joerg Mayer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).