diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-11-16 03:10:56 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-11-16 03:10:56 +0000 |
commit | 5fe95d1b660bed238f8f53d6c7360f44b5ce9824 (patch) | |
tree | f75dc7eaabf7bd7baacc8cc8440484d88d3666e2 /package/mac80211/patches/010-add-mgmt-iface.patch | |
parent | a4d094be2ac657698039b16163822b8ccd32f0d9 (diff) |
fix up hostapd for mac80211
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@9554 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/mac80211/patches/010-add-mgmt-iface.patch')
-rw-r--r-- | package/mac80211/patches/010-add-mgmt-iface.patch | 688 |
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 000000000..eae5ff6d5 --- /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; |