mac80211: move interface type to vif structure
[linux-2.6-block.git] / net / mac80211 / ieee80211.c
index 373e8b728782fef63ad2241f5a4459f970d273e3..c9981701ef686751fb7d9c5d3f1495f90fbde224 100644 (file)
@@ -24,7 +24,6 @@
 #include <net/net_namespace.h>
 #include <net/cfg80211.h>
 
-#include "ieee80211_common.h"
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
 #include "wep.h"
@@ -35,6 +34,8 @@
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
+#define SUPP_MCS_SET_LEN 16
+
 /*
  * For seeing transmitted packets on monitor interfaces
  * we have a radiotap header too.
@@ -123,151 +124,6 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev)
        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->destructor = ieee80211_if_free;
-}
-
 /* regular interfaces */
 
 static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
@@ -321,21 +177,21 @@ static int ieee80211_open(struct net_device *dev)
                        /*
                         * check whether it may have the same address
                         */
-                       if (!identical_mac_addr_allowed(sdata->type,
-                                                       nsdata->type))
+                       if (!identical_mac_addr_allowed(sdata->vif.type,
+                                                       nsdata->vif.type))
                                return -ENOTUNIQ;
 
                        /*
                         * can only add VLANs to enabled APs
                         */
-                       if (sdata->type == IEEE80211_IF_TYPE_VLAN &&
-                           nsdata->type == IEEE80211_IF_TYPE_AP &&
+                       if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
+                           nsdata->vif.type == IEEE80211_IF_TYPE_AP &&
                            netif_running(nsdata->dev))
                                sdata->u.vlan.ap = nsdata;
                }
        }
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_WDS:
                if (is_zero_ether_addr(sdata->u.wds.remote_addr))
                        return -ENOLINK;
@@ -345,7 +201,6 @@ static int ieee80211_open(struct net_device *dev)
                        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:
@@ -363,9 +218,11 @@ static int ieee80211_open(struct net_device *dev)
                        res = local->ops->start(local_to_hw(local));
                if (res)
                        return res;
+               ieee80211_hw_config(local);
+               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
        }
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_VLAN:
                list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
                /* no need to tell driver */
@@ -379,7 +236,6 @@ static int ieee80211_open(struct net_device *dev)
                        netif_tx_unlock_bh(local->mdev);
 
                        local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-                       ieee80211_hw_config(local);
                }
                break;
        case IEEE80211_IF_TYPE_STA:
@@ -387,8 +243,8 @@ static int ieee80211_open(struct net_device *dev)
                sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
                /* fall through */
        default:
-               conf.if_id = dev->ifindex;
-               conf.type = sdata->type;
+               conf.vif = &sdata->vif;
+               conf.type = sdata->vif.type;
                conf.mac_addr = dev->dev_addr;
                res = local->ops->add_interface(local_to_hw(local), &conf);
                if (res && !local->open_count && local->ops->stop)
@@ -400,8 +256,8 @@ static int ieee80211_open(struct net_device *dev)
                ieee80211_reset_erp_info(dev);
                ieee80211_enable_keys(sdata);
 
-               if (sdata->type == IEEE80211_IF_TYPE_STA &&
-                   !local->user_space_mlme)
+               if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
+                   !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
                        netif_carrier_off(dev);
                else
                        netif_carrier_on(dev);
@@ -410,14 +266,21 @@ static int ieee80211_open(struct net_device *dev)
        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);
        }
 
+       /*
+        * set_multicast_list will be invoked by the networking core
+        * which will check whether any increments here were done in
+        * error and sync them down to the hardware as filter flags.
+        */
+       if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+               atomic_inc(&local->iff_allmultis);
+
+       if (sdata->flags & IEEE80211_SDATA_PROMISC)
+               atomic_inc(&local->iff_promiscs);
+
        local->open_count++;
 
        netif_start_queue(dev);
@@ -430,15 +293,36 @@ static int ieee80211_stop(struct net_device *dev)
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_if_init_conf conf;
+       struct sta_info *sta;
+       int i;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       list_for_each_entry(sta, &local->sta_list, list) {
+               for (i = 0; i <  STA_TID_NUM; i++)
+                       ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
+                                               i, WLAN_BACK_RECIPIENT,
+                                               WLAN_REASON_QSTA_LEAVE_QBSS);
+       }
+
        netif_stop_queue(dev);
 
+       /*
+        * Don't count this interface for promisc/allmulti while it
+        * is down. dev_mc_unsync() will invoke set_multicast_list
+        * on the master interface which will sync these down to the
+        * hardware as filter flags.
+        */
+       if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+               atomic_dec(&local->iff_allmultis);
+
+       if (sdata->flags & IEEE80211_SDATA_PROMISC)
+               atomic_dec(&local->iff_promiscs);
+
        dev_mc_unsync(local->mdev, dev);
 
        /* down all dependent devices, that is VLANs */
-       if (sdata->type == IEEE80211_IF_TYPE_AP) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
                struct ieee80211_sub_if_data *vlan, *tmp;
 
                list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
@@ -449,7 +333,7 @@ static int ieee80211_stop(struct net_device *dev)
 
        local->open_count--;
 
-       switch (sdata->type) {
+       switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_VLAN:
                list_del(&sdata->u.vlan.list);
                sdata->u.vlan.ap = NULL;
@@ -462,8 +346,7 @@ static int ieee80211_stop(struct net_device *dev)
                        ieee80211_configure_filter(local);
                        netif_tx_unlock_bh(local->mdev);
 
-                       local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-                       ieee80211_hw_config(local);
+                       local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
                }
                break;
        case IEEE80211_IF_TYPE_STA:
@@ -479,16 +362,24 @@ static int ieee80211_stop(struct net_device *dev)
                synchronize_rcu();
                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);
+               if (local->scan_dev == sdata->dev) {
+                       if (!local->ops->hw_scan) {
+                               local->sta_sw_scanning = 0;
+                               cancel_delayed_work(&local->scan_work);
+                       } else
+                               local->sta_hw_scanning = 0;
                }
+
                flush_workqueue(local->hw.workqueue);
+
+               sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
+               kfree(sdata->u.sta.extra_ie);
+               sdata->u.sta.extra_ie = NULL;
+               sdata->u.sta.extra_ie_len = 0;
                /* fall through */
        default:
-               conf.if_id = dev->ifindex;
-               conf.type = sdata->type;
+               conf.vif = &sdata->vif;
+               conf.type = sdata->vif.type;
                conf.mac_addr = dev->dev_addr;
                /* disable all keys for as long as this netdev is down */
                ieee80211_disable_keys(sdata);
@@ -499,12 +390,11 @@ static int ieee80211_stop(struct net_device *dev)
                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));
 
+               ieee80211_led_radio(local, 0);
+
                tasklet_disable(&local->tx_pending_tasklet);
                tasklet_disable(&local->tasklet);
        }
@@ -520,8 +410,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
 
        allmulti = !!(dev->flags & IFF_ALLMULTI);
        promisc = !!(dev->flags & IFF_PROMISC);
-       sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
-       sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
+       sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
+       sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
 
        if (allmulti != sdata_allmulti) {
                if (dev->flags & IFF_ALLMULTI)
@@ -550,11 +440,10 @@ static const struct header_ops ieee80211_header_ops = {
        .cache_update   = eth_header_cache_update,
 };
 
-/* Must not be called for mdev and apdev */
+/* Must not be called for mdev */
 void ieee80211_if_setup(struct net_device *dev)
 {
        ether_setup(dev);
-       dev->header_ops = &ieee80211_header_ops;
        dev->hard_start_xmit = ieee80211_subif_start_xmit;
        dev->wireless_handlers = &ieee80211_iw_handler_def;
        dev->set_multicast_list = ieee80211_set_multicast_list;
@@ -613,20 +502,20 @@ static int __ieee80211_if_config(struct net_device *dev,
                return 0;
 
        memset(&conf, 0, sizeof(conf));
-       conf.type = sdata->type;
-       if (sdata->type == IEEE80211_IF_TYPE_STA ||
-           sdata->type == IEEE80211_IF_TYPE_IBSS) {
+       conf.type = sdata->vif.type;
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                conf.bssid = sdata->u.sta.bssid;
                conf.ssid = sdata->u.sta.ssid;
                conf.ssid_len = sdata->u.sta.ssid_len;
-       } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+       } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
                conf.ssid = sdata->u.ap.ssid;
                conf.ssid_len = sdata->u.ap.ssid_len;
                conf.beacon = beacon;
                conf.beacon_control = control;
        }
        return local->ops->config_interface(local_to_hw(local),
-                                          dev->ifindex, &conf);
+                                           &sdata->vif, &conf);
 }
 
 int ieee80211_if_config(struct net_device *dev)
@@ -638,11 +527,13 @@ int ieee80211_if_config_beacon(struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_tx_control control;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sk_buff *skb;
 
        if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
                return 0;
-       skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
+       skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
+                                  &control);
        if (!skb)
                return -ENOMEM;
        return __ieee80211_if_config(dev, skb, &control);
@@ -654,7 +545,7 @@ int ieee80211_hw_config(struct ieee80211_local *local)
        struct ieee80211_channel *chan;
        int ret = 0;
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning) {
                chan = local->scan_channel;
                mode = local->scan_hw_mode;
        } else {
@@ -688,6 +579,55 @@ int ieee80211_hw_config(struct ieee80211_local *local)
        return ret;
 }
 
+/**
+ * ieee80211_hw_config_ht should be used only after legacy configuration
+ * has been determined, as ht configuration depends upon the hardware's
+ * HT abilities for a _specific_ band.
+ */
+int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
+                          struct ieee80211_ht_info *req_ht_cap,
+                          struct ieee80211_ht_bss_info *req_bss_cap)
+{
+       struct ieee80211_conf *conf = &local->hw.conf;
+       struct ieee80211_hw_mode *mode = conf->mode;
+       int i;
+
+       /* HT is not supported */
+       if (!mode->ht_info.ht_supported) {
+               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+               return -EOPNOTSUPP;
+       }
+
+       /* disable HT */
+       if (!enable_ht) {
+               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+       } else {
+               conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+               conf->ht_conf.cap = req_ht_cap->cap & mode->ht_info.cap;
+               conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+               conf->ht_conf.cap |=
+                       mode->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+               conf->ht_bss_conf.primary_channel =
+                       req_bss_cap->primary_channel;
+               conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+               conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+               for (i = 0; i < SUPP_MCS_SET_LEN; i++)
+                       conf->ht_conf.supp_mcs_set[i] =
+                               mode->ht_info.supp_mcs_set[i] &
+                                 req_ht_cap->supp_mcs_set[i];
+
+               /* In STA mode, this gives us indication
+                * to the AP's mode of operation */
+               conf->ht_conf.ht_supported = 1;
+               conf->ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+               conf->ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+       }
+
+       local->ops->conf_ht(local_to_hw(local), &local->hw.conf);
+
+       return 0;
+}
+
 void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -763,7 +703,7 @@ static void ieee80211_tasklet_handler(unsigned long data)
                case IEEE80211_RX_MSG:
                        /* status is in skb->cb */
                        memcpy(&rx_status, skb->cb, sizeof(rx_status));
-                       /* Clear skb->type in order to not confuse kernel
+                       /* Clear skb->pkt_type in order to not confuse kernel
                         * netstack. */
                        skb->pkt_type = 0;
                        __ieee80211_rx(local_to_hw(local), skb, &rx_status);
@@ -798,7 +738,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
        struct ieee80211_tx_packet_data *pkt_data;
 
        pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       pkt_data->ifindex = control->ifindex;
+       pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
        pkt_data->flags = 0;
        if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
                pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
@@ -806,8 +746,8 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
                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;
+       if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
+               pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
        pkt_data->queue = control->queue;
 
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -860,7 +800,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
        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;
@@ -936,10 +875,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                        sta_info_put(sta);
                        return;
                }
-       } else {
-               /* FIXME: STUPID to call this with both local and local->mdev */
-               rate_control_tx_status(local, local->mdev, skb, status);
-       }
+       } else
+               rate_control_tx_status(local->mdev, skb, status);
 
        ieee80211_led_tx(local, 0);
 
@@ -975,29 +912,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                        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;
@@ -1045,7 +962,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                if (!monitors || !skb)
                        goto out;
 
-               if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+               if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
                        if (!netif_running(sdata->dev))
                                continue;
                        monitors--;
@@ -1167,7 +1084,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        mdev->header_ops = &ieee80211_header_ops;
        mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
-       sdata->type = IEEE80211_IF_TYPE_AP;
+       sdata->vif.type = IEEE80211_IF_TYPE_AP;
        sdata->dev = mdev;
        sdata->local = local;
        sdata->u.ap.force_unicast_rateidx = -1;
@@ -1249,7 +1166,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
        ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
 
-       result = ieee80211_init_rate_ctrl_alg(local, NULL);
+       result = ieee80211_init_rate_ctrl_alg(local,
+                                             hw->rate_control_algorithm);
        if (result < 0) {
                printk(KERN_DEBUG "%s: Failed to initialize rate control "
                       "algorithm\n", wiphy_name(local->hw.wiphy));
@@ -1344,8 +1262,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
        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
@@ -1412,21 +1328,39 @@ static int __init ieee80211_init(void)
 
        BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
 
+       ret = rc80211_simple_init();
+       if (ret)
+               goto fail;
+
+       ret = rc80211_pid_init();
+       if (ret)
+               goto fail_simple;
+
        ret = ieee80211_wme_register();
        if (ret) {
                printk(KERN_DEBUG "ieee80211_init: failed to "
                       "initialize WME (err=%d)\n", ret);
-               return ret;
+               goto fail_pid;
        }
 
        ieee80211_debugfs_netdev_init();
        ieee80211_regdomain_init();
 
        return 0;
+
+ fail_pid:
+       rc80211_simple_exit();
+ fail_simple:
+       rc80211_pid_exit();
+ fail:
+       return ret;
 }
 
 static void __exit ieee80211_exit(void)
 {
+       rc80211_simple_exit();
+       rc80211_pid_exit();
+
        ieee80211_wme_unregister();
        ieee80211_debugfs_netdev_exit();
 }