aboutsummaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/010-add-mgmt-iface.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/010-add-mgmt-iface.patch')
-rw-r--r--package/mac80211/patches/010-add-mgmt-iface.patch688
1 files changed, 688 insertions, 0 deletions
diff --git a/package/mac80211/patches/010-add-mgmt-iface.patch b/package/mac80211/patches/010-add-mgmt-iface.patch
new file mode 100644
index 0000000000..eae5ff6d5e
--- /dev/null
+++ b/package/mac80211/patches/010-add-mgmt-iface.patch
@@ -0,0 +1,688 @@
+---
+ include/net/mac80211.h | 1
+ net/mac80211/ieee80211.c | 198 ++++++++++++++++++++++++++++++++++++++--
+ net/mac80211/ieee80211_common.h | 64 ++++++++++++
+ net/mac80211/ieee80211_i.h | 9 +
+ net/mac80211/ieee80211_iface.c | 66 +++++++++++++
+ net/mac80211/ieee80211_ioctl.c | 21 ++++
+ net/mac80211/ieee80211_rate.c | 3
+ net/mac80211/ieee80211_rate.h | 2
+ net/mac80211/ieee80211_sta.c | 2
+ net/mac80211/rx.c | 29 ++++-
+ net/mac80211/tx.c | 14 ++
+ net/mac80211/wme.c | 10 +-
+ 12 files changed, 399 insertions(+), 20 deletions(-)
+
+Index: mac80211/include/net/mac80211.h
+===================================================================
+--- mac80211.orig/include/net/mac80211.h 2007-11-11 15:15:42.824034853 +0100
++++ mac80211/include/net/mac80211.h 2007-11-11 15:15:53.784659457 +0100
+@@ -472,6 +472,7 @@
+ enum ieee80211_if_types {
+ IEEE80211_IF_TYPE_INVALID,
+ IEEE80211_IF_TYPE_AP,
++ IEEE80211_IF_TYPE_MGMT,
+ IEEE80211_IF_TYPE_STA,
+ IEEE80211_IF_TYPE_IBSS,
+ IEEE80211_IF_TYPE_MNTR,
+Index: mac80211/net/mac80211/ieee80211.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211.c 2007-11-11 15:15:51.536531354 +0100
++++ mac80211/net/mac80211/ieee80211.c 2007-11-11 15:16:22.214279577 +0100
+@@ -23,6 +23,7 @@
+ #include <linux/bitmap.h>
+ #include <net/cfg80211.h>
+
++#include "ieee80211_common.h"
+ #include "ieee80211_i.h"
+ #include "ieee80211_rate.h"
+ #include "wep.h"
+@@ -121,6 +122,152 @@
+ ieee80211_configure_filter(local);
+ }
+
++/* 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:
++ 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;
++ 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 net_device *dev = local->apdev;
++
++ skb->dev = dev;
++
++ 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);
++
++ dev->stats.rx_packets++;
++ dev->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);
++}
++
++static int ieee80211_mgmt_open(struct net_device *dev)
++{
++ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
++
++ if (!netif_running(local->mdev))
++ return -EOPNOTSUPP;
++ return 0;
++}
++
++static int ieee80211_mgmt_stop(struct net_device *dev)
++{
++ return 0;
++}
++
++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;
++ }
++
++#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;
++}
++
++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->open = ieee80211_mgmt_open;
++ dev->stop = ieee80211_mgmt_stop;
++ dev->type = ARPHRD_IEEE80211_PRISM;
++ dev->hard_header_parse = &header_parse_80211;
++ dev->destructor = ieee80211_if_free;
++}
++
+ /* regular interfaces */
+
+ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+@@ -198,6 +345,7 @@
+ return -ENOLINK;
+ break;
+ case IEEE80211_IF_TYPE_AP:
++ case IEEE80211_IF_TYPE_MGMT:
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_MNTR:
+ case IEEE80211_IF_TYPE_IBSS:
+@@ -262,6 +410,10 @@
+ if (local->open_count == 0) {
+ res = dev_open(local->mdev);
+ WARN_ON(res);
++ if (local->apdev) {
++ res = dev_open(local->apdev);
++ WARN_ON(res);
++ }
+ tasklet_enable(&local->tx_pending_tasklet);
+ tasklet_enable(&local->tasklet);
+ }
+@@ -347,6 +499,9 @@
+ 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));
+
+@@ -646,6 +801,8 @@
+ pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+ if (control->flags & IEEE80211_TXCTL_REQUEUE)
+ pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
++ if (control->type == IEEE80211_IF_TYPE_MGMT)
++ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
+ pkt_data->queue = control->queue;
+
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+@@ -698,6 +855,7 @@
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_local *local = hw_to_local(hw);
+ u16 frag, type;
++ u32 msg_type;
+ struct ieee80211_tx_status_rtap_hdr *rthdr;
+ struct ieee80211_sub_if_data *sdata;
+ int monitors;
+@@ -812,9 +970,29 @@
+ local->dot11FailedCount++;
+ }
+
++ msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
++ ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
++
+ /* this was a transmitted frame, but now we want to reuse it */
+ skb_orphan(skb);
+
++ if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) &&
++ local->apdev) {
++ if (local->monitors) {
++ skb2 = skb_clone(skb, GFP_ATOMIC);
++ } else {
++ skb2 = skb;
++ skb = NULL;
++ }
++
++ if (skb2)
++ /* Send frame to hostapd */
++ ieee80211_rx_mgmt(local, skb2, NULL, msg_type);
++
++ if (!skb)
++ return;
++ }
++
+ if (!local->monitors) {
+ dev_kfree_skb(skb);
+ return;
+@@ -1161,6 +1339,8 @@
+ BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
+
+ local->reg_state = IEEE80211_DEV_UNREGISTERED;
++ if (local->apdev)
++ ieee80211_if_del_mgmt(local);
+
+ /*
+ * At this point, interface list manipulations are fine
+Index: mac80211/net/mac80211/ieee80211_i.h
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_i.h 2007-11-11 15:15:42.840035769 +0100
++++ mac80211/net/mac80211/ieee80211_i.h 2007-11-11 15:15:53.792659922 +0100
+@@ -142,6 +142,7 @@
+ * when using CTS protection with IEEE 802.11g. */
+ struct ieee80211_rate *last_frag_rate;
+ int last_frag_hwrate;
++ int mgmt_interface;
+
+ /* Extra fragments (in addition to the first fragment
+ * in skb) */
+@@ -163,6 +164,7 @@
+ #define IEEE80211_TXPD_REQ_TX_STATUS BIT(0)
+ #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
+ #define IEEE80211_TXPD_REQUEUE BIT(2)
++#define IEEE80211_TXPD_MGMT_IFACE BIT(3)
+ /* Stored in sk_buff->cb */
+ struct ieee80211_tx_packet_data {
+ int ifindex;
+@@ -408,6 +410,7 @@
+ struct list_head modes_list;
+
+ struct net_device *mdev; /* wmaster# - "master" 802.11 device */
++ struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
+ int open_count;
+ int monitors;
+ unsigned int filter_flags; /* FIF_* */
+@@ -701,11 +704,14 @@
+ 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);
++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,
+ struct ieee80211_hw_mode *mode);
+ void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
+ 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);
+ struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
+ int phymode, int hwrate);
+
+@@ -772,6 +778,8 @@
+ int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
+ void ieee80211_if_free(struct net_device *dev);
+ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
++int ieee80211_if_add_mgmt(struct ieee80211_local *local);
++void ieee80211_if_del_mgmt(struct ieee80211_local *local);
+
+ /* regdomain.c */
+ void ieee80211_regdomain_init(void);
+@@ -788,6 +796,7 @@
+ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ 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);
+
+ /* utility functions/constants */
+ extern void *mac80211_wiphy_privid; /* for wiphy privid */
+Index: mac80211/net/mac80211/ieee80211_iface.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:42.848036222 +0100
++++ mac80211/net/mac80211/ieee80211_iface.c 2007-11-11 15:15:53.796660158 +0100
+@@ -96,6 +96,66 @@
+ return ret;
+ }
+
++int ieee80211_if_add_mgmt(struct ieee80211_local *local)
++{
++ struct net_device *ndev;
++ struct ieee80211_sub_if_data *nsdata;
++ int ret;
++
++ ASSERT_RTNL();
++
++ ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
++ ieee80211_if_mgmt_setup);
++ if (!ndev)
++ return -ENOMEM;
++ ret = dev_alloc_name(ndev, ndev->name);
++ if (ret < 0)
++ goto fail;
++
++ memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
++ SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
++
++ nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
++ ndev->ieee80211_ptr = &nsdata->wdev;
++ nsdata->wdev.wiphy = local->hw.wiphy;
++ nsdata->type = IEEE80211_IF_TYPE_MGMT;
++ nsdata->dev = ndev;
++ nsdata->local = local;
++ ieee80211_if_sdata_init(nsdata);
++
++ ret = register_netdevice(ndev);
++ if (ret)
++ goto fail;
++
++ /*
++ * Called even when register_netdevice fails, it would
++ * oops if assigned before initialising the rest.
++ */
++ ndev->uninit = ieee80211_if_reinit;
++
++ ieee80211_debugfs_add_netdev(nsdata);
++
++ if (local->open_count > 0)
++ dev_open(ndev);
++ local->apdev = ndev;
++ return 0;
++
++fail:
++ free_netdev(ndev);
++ return ret;
++}
++
++void ieee80211_if_del_mgmt(struct ieee80211_local *local)
++{
++ struct net_device *apdev;
++
++ ASSERT_RTNL();
++ apdev = local->apdev;
++ ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
++ local->apdev = NULL;
++ unregister_netdevice(apdev);
++}
++
+ void ieee80211_if_set_type(struct net_device *dev, int type)
+ {
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+@@ -183,6 +243,9 @@
+ ieee80211_if_sdata_deinit(sdata);
+
+ switch (sdata->type) {
++ case IEEE80211_IF_TYPE_MGMT:
++ /* nothing to do */
++ break;
+ case IEEE80211_IF_TYPE_INVALID:
+ /* cannot happen */
+ WARN_ON(1);
+@@ -294,8 +357,11 @@
+
+ void ieee80211_if_free(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);
+
++ /* local->apdev must be NULL when freeing management interface */
++ BUG_ON(dev == local->apdev);
+ ieee80211_if_sdata_deinit(sdata);
+ free_netdev(dev);
+ }
+Index: mac80211/net/mac80211/ieee80211_rate.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:42.852036451 +0100
++++ mac80211/net/mac80211/ieee80211_rate.c 2007-11-11 15:15:53.800660386 +0100
+@@ -145,7 +145,8 @@
+ struct rate_control_ref *ref, *old;
+
+ ASSERT_RTNL();
+- if (local->open_count || netif_running(local->mdev))
++ if (local->open_count || netif_running(local->mdev) ||
++ (local->apdev && netif_running(local->apdev)))
+ return -EBUSY;
+
+ ref = rate_control_alloc(name, local);
+Index: mac80211/net/mac80211/ieee80211_rate.h
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:42.860036908 +0100
++++ mac80211/net/mac80211/ieee80211_rate.h 2007-11-11 15:15:53.800660386 +0100
+@@ -30,6 +30,8 @@
+
+ /* parameters from the caller to rate_control_get_rate(): */
+ struct ieee80211_hw_mode *mode;
++ int mgmt_data; /* this is data frame that is used for management
++ * (e.g., IEEE 802.1X EAPOL) */
+ u16 ethertype;
+ };
+
+Index: mac80211/net/mac80211/ieee80211_sta.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:42.868037362 +0100
++++ mac80211/net/mac80211/ieee80211_sta.c 2007-11-11 15:15:53.800660386 +0100
+@@ -475,6 +475,8 @@
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = sdata->dev->ifindex;
++ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
++ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
+ if (!encrypt)
+ pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+
+Index: mac80211/net/mac80211/rx.c
+===================================================================
+--- mac80211.orig/net/mac80211/rx.c 2007-11-11 15:15:42.872037591 +0100
++++ mac80211/net/mac80211/rx.c 2007-11-11 15:15:53.804660611 +0100
+@@ -19,6 +19,7 @@
+
+ #include "ieee80211_i.h"
+ #include "ieee80211_led.h"
++#include "ieee80211_common.h"
+ #include "wep.h"
+ #include "wpa.h"
+ #include "tkip.h"
+@@ -411,7 +412,12 @@
+ return TXRX_DROP;
+ }
+
+- return TXRX_DROP;
++ if (!rx->local->apdev)
++ return TXRX_DROP;
++
++ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
++ ieee80211_msg_sta_not_assoc);
++ return TXRX_QUEUED;
+ }
+
+ return TXRX_CONTINUE;
+@@ -953,8 +959,15 @@
+ {
+ if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
+ rx->sdata->type != IEEE80211_IF_TYPE_STA &&
+- (rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
+- return TXRX_CONTINUE;
++ (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
++ /* Pass both encrypted and unencrypted EAPOL frames to user
++ * space for processing. */
++ if (!rx->local->apdev)
++ return TXRX_DROP;
++ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
++ ieee80211_msg_normal);
++ return TXRX_QUEUED;
++ }
+
+ if (unlikely(rx->sdata->ieee802_1x &&
+ (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+@@ -1196,8 +1209,13 @@
+ sdata->type == IEEE80211_IF_TYPE_IBSS) &&
+ !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
+ ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+- else
+- return TXRX_DROP;
++ else {
++ /* Management frames are sent to hostapd for processing */
++ if (!rx->local->apdev)
++ return TXRX_DROP;
++ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
++ ieee80211_msg_normal);
++ }
+
+ return TXRX_QUEUED;
+ }
+@@ -1407,6 +1425,7 @@
+ /* take everything */
+ break;
+ case IEEE80211_IF_TYPE_INVALID:
++ case IEEE80211_IF_TYPE_MGMT:
+ /* should never get here */
+ WARN_ON(1);
+ break;
+Index: mac80211/net/mac80211/tx.c
+===================================================================
+--- mac80211.orig/net/mac80211/tx.c 2007-11-11 15:15:42.880038048 +0100
++++ mac80211/net/mac80211/tx.c 2007-11-11 15:15:53.804660611 +0100
+@@ -258,7 +258,7 @@
+ return TXRX_CONTINUE;
+ }
+
+- if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&
++ if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x &&
+ !(sta_flags & WLAN_STA_AUTHORIZED))) {
+ #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
+@@ -568,6 +568,8 @@
+ memset(&extra, 0, sizeof(extra));
+ extra.mode = tx->u.tx.mode;
+ extra.ethertype = tx->ethertype;
++ extra.mgmt_data = tx->sdata &&
++ tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
+
+ tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
+ tx->skb, &extra);
+@@ -1076,7 +1078,7 @@
+ }
+
+ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
+- struct ieee80211_tx_control *control)
++ struct ieee80211_tx_control *control, int mgmt)
+ {
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+@@ -1107,6 +1109,7 @@
+ rcu_read_lock();
+
+ sta = tx.sta;
++ tx.u.tx.mgmt_interface = mgmt;
+ tx.u.tx.mode = local->hw.conf.mode;
+
+ for (handler = local->tx_handlers; *handler != NULL;
+@@ -1253,7 +1256,8 @@
+ control.flags |= IEEE80211_TXCTL_REQUEUE;
+ control.queue = pkt_data->queue;
+
+- ret = ieee80211_tx(odev, skb, &control);
++ ret = ieee80211_tx(odev, skb, &control,
++ control.type == IEEE80211_IF_TYPE_MGMT);
+ dev_put(odev);
+
+ return ret;
+@@ -1498,6 +1502,8 @@
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = dev->ifindex;
++ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
++ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
+
+ skb->dev = local->mdev;
+ dev->stats.tx_packets++;
+@@ -1555,6 +1561,8 @@
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = sdata->dev->ifindex;
++ if (sdata->type == IEEE80211_IF_TYPE_MGMT)
++ pkt_data->flags |= IEEE80211_TXPD_MGMT_IFACE;
+
+ skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
+ skb->dev = sdata->local->mdev;
+Index: mac80211/net/mac80211/wme.c
+===================================================================
+--- mac80211.orig/net/mac80211/wme.c 2007-11-11 15:15:42.888038502 +0100
++++ mac80211/net/mac80211/wme.c 2007-11-11 15:15:53.804660611 +0100
+@@ -94,6 +94,8 @@
+ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
+ {
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
++ struct ieee80211_tx_packet_data *pkt_data =
++ (struct ieee80211_tx_packet_data *) skb->cb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ unsigned short fc = le16_to_cpu(hdr->frame_control);
+ int qos;
+@@ -106,8 +108,12 @@
+ return IEEE80211_TX_QUEUE_DATA0;
+ }
+
+- if (0 /* injected */) {
+- /* use AC from radiotap */
++ if (unlikely(pkt_data->flags & IEEE80211_TXPD_MGMT_IFACE)) {
++ /* Data frames from hostapd (mainly, EAPOL) use AC_VO
++ * and they will include QoS control fields if
++ * the target STA is using WME. */
++ skb->priority = 7;
++ return ieee802_1d_to_ac[skb->priority];
+ }
+
+ /* is this a QoS frame? */
+Index: mac80211/net/mac80211/ieee80211_ioctl.c
+===================================================================
+--- mac80211.orig/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:51.532531127 +0100
++++ mac80211/net/mac80211/ieee80211_ioctl.c 2007-11-11 15:15:53.808660833 +0100
+@@ -840,16 +840,29 @@
+ void *wrqu, char *extra)
+ {
+ struct ieee80211_sub_if_data *sdata;
++ struct ieee80211_local *local;
+ int *i = (int *) extra;
+ int param = *i;
++ int value = *(i + 1);
+ int ret = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++ local = sdata->local;
+
+ switch (param) {
++ case PRISM2_PARAM_MGMT_IF:
++ if (value == 1) {
++ if (!local->apdev)
++ ret = ieee80211_if_add_mgmt(local);
++ } else if (value == 0) {
++ if (local->apdev)
++ ieee80211_if_del_mgmt(local);
++ } else
++ ret = -EINVAL;
++ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+@@ -864,12 +877,20 @@
+ void *wrqu, char *extra)
+ {
+ struct ieee80211_sub_if_data *sdata;
++ struct ieee80211_local *local;
+ int *param = (int *) extra;
+ int ret = 0;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++ local = sdata->local;
+
+ switch (*param) {
++ case PRISM2_PARAM_MGMT_IF:
++ if (local->apdev)
++ *param = local->apdev->ifindex;
++ else
++ ret = -ENOENT;
++ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;