mac80211: allow station add/remove to sleep
[pandora-kernel.git] / net / mac80211 / tx.c
index eaa4118..cbe53ed 100644 (file)
@@ -180,6 +180,71 @@ static int inline is_ieee80211_device(struct ieee80211_local *local,
 }
 
 /* tx handlers */
+static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_local *local = tx->local;
+       struct ieee80211_if_managed *ifmgd;
+
+       /* driver doesn't support power save */
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+               return TX_CONTINUE;
+
+       /* hardware does dynamic power save */
+       if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+               return TX_CONTINUE;
+
+       /* dynamic power save disabled */
+       if (local->hw.conf.dynamic_ps_timeout <= 0)
+               return TX_CONTINUE;
+
+       /* we are scanning, don't enable power save */
+       if (local->scanning)
+               return TX_CONTINUE;
+
+       if (!local->ps_sdata)
+               return TX_CONTINUE;
+
+       /* No point if we're going to suspend */
+       if (local->quiescing)
+               return TX_CONTINUE;
+
+       /* dynamic ps is supported only in managed mode */
+       if (tx->sdata->vif.type != NL80211_IFTYPE_STATION)
+               return TX_CONTINUE;
+
+       ifmgd = &tx->sdata->u.mgd;
+
+       /*
+        * Don't wakeup from power save if u-apsd is enabled, voip ac has
+        * u-apsd enabled and the frame is in voip class. This effectively
+        * means that even if all access categories have u-apsd enabled, in
+        * practise u-apsd is only used with the voip ac. This is a
+        * workaround for the case when received voip class packets do not
+        * have correct qos tag for some reason, due the network or the
+        * peer application.
+        *
+        * Note: local->uapsd_queues access is racy here. If the value is
+        * changed via debugfs, user needs to reassociate manually to have
+        * everything in sync.
+        */
+       if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
+           && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+           && skb_get_queue_mapping(tx->skb) == 0)
+               return TX_CONTINUE;
+
+       if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+               ieee80211_stop_queues_by_reason(&local->hw,
+                                               IEEE80211_QUEUE_STOP_REASON_PS);
+               ieee80211_queue_work(&local->hw,
+                                    &local->dynamic_ps_disable_work);
+       }
+
+       mod_timer(&local->dynamic_ps_timer, jiffies +
+                 msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+
+       return TX_CONTINUE;
+}
 
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
@@ -223,7 +288,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                        printk(KERN_DEBUG "%s: dropped data frame to not "
                               "associated station %pM\n",
-                              tx->dev->name, hdr->addr1);
+                              tx->sdata->name, hdr->addr1);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
                        I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
                        return TX_DROP;
@@ -317,12 +382,11 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
        if (!atomic_read(&tx->sdata->bss->num_sta_ps))
                return TX_CONTINUE;
 
-       /* buffered in hardware */
-       if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) {
-               info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
+       info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
 
+       /* device releases frame after DTIM beacon */
+       if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
                return TX_CONTINUE;
-       }
 
        /* buffered in mac80211 */
        if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
@@ -332,7 +396,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n",
-                              tx->dev->name);
+                              tx->sdata->name);
 #endif
                dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
        } else
@@ -367,15 +431,16 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        u32 staflags;
 
-       if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control)
-                       || ieee80211_is_auth(hdr->frame_control)
-                       || ieee80211_is_assoc_resp(hdr->frame_control)
-                       || ieee80211_is_reassoc_resp(hdr->frame_control)))
+       if (unlikely(!sta ||
+                    ieee80211_is_probe_resp(hdr->frame_control) ||
+                    ieee80211_is_auth(hdr->frame_control) ||
+                    ieee80211_is_assoc_resp(hdr->frame_control) ||
+                    ieee80211_is_reassoc_resp(hdr->frame_control)))
                return TX_CONTINUE;
 
        staflags = get_sta_flags(sta);
 
-       if (unlikely((staflags & WLAN_STA_PS) &&
+       if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
                     !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
@@ -391,15 +456,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                        if (net_ratelimit()) {
                                printk(KERN_DEBUG "%s: STA %pM TX "
                                       "buffer full - dropping oldest frame\n",
-                                      tx->dev->name, sta->sta.addr);
+                                      tx->sdata->name, sta->sta.addr);
                        }
 #endif
                        dev_kfree_skb(old);
                } else
                        tx->local->total_ps_buffered++;
 
-               /* Queue frame to be sent after STA sends an PS Poll frame */
-               if (skb_queue_empty(&sta->ps_tx_buf))
+               /*
+                * Queue frame to be sent after STA wakes up/polls,
+                * but don't set the TIM bit if the driver is blocking
+                * wakeup or poll response transmissions anyway.
+                */
+               if (skb_queue_empty(&sta->ps_tx_buf) &&
+                   !(staflags & WLAN_STA_PS_DRIVER))
                        sta_info_set_tim_bit(sta);
 
                info->control.jiffies = jiffies;
@@ -409,9 +479,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                return TX_QUEUED;
        }
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
+       else if (unlikely(staflags & WLAN_STA_PS_STA)) {
                printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
-                      "set -> send frame\n", tx->dev->name,
+                      "set -> send frame\n", tx->sdata->name,
                       sta->sta.addr);
        }
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
@@ -459,6 +529,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                tx->key = NULL;
 
        if (tx->key) {
+               bool skip_hw = false;
+
                tx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
 
@@ -475,16 +547,32 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                            !ieee80211_use_mfp(hdr->frame_control, tx->sta,
                                               tx->skb))
                                tx->key = NULL;
+                       else
+                               skip_hw = (tx->key->conf.flags &
+                                          IEEE80211_KEY_FLAG_SW_MGMT) &&
+                                       ieee80211_is_mgmt(hdr->frame_control);
                        break;
                case ALG_AES_CMAC:
                        if (!ieee80211_is_mgmt(hdr->frame_control))
                                tx->key = NULL;
                        break;
                }
+
+               if (!skip_hw && tx->key &&
+                   tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
+                       info->control.hw_key = &tx->key->conf;
        }
 
-       if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       return TX_CONTINUE;
+}
+
+static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_sta(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+       if (tx->sta && tx->sta->uploaded)
+               info->control.sta = &tx->sta->sta;
 
        return TX_CONTINUE;
 }
@@ -514,7 +602,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        txrc.bss_conf = &tx->sdata->vif.bss_conf;
        txrc.skb = tx->skb;
        txrc.reported_rate.idx = -1;
-       txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
+       txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band];
+       if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
+               txrc.max_rate_idx = -1;
+       else
+               txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+       txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP;
 
        /* set up RTS protection if desired */
        if (len > tx->local->hw.wiphy->rts_threshold) {
@@ -544,7 +637,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
                 "%s: Dropped data frame as no usable bitrate found while "
                 "scanning and associated. Target station: "
                 "%pM on %d GHz band\n",
-                tx->dev->name, hdr->addr1,
+                tx->sdata->name, hdr->addr1,
                 tx->channel->band ? 5 : 2))
                return TX_DROP;
 
@@ -658,17 +751,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        return TX_CONTINUE;
 }
 
-static ieee80211_tx_result debug_noinline
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
-{
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-
-       if (tx->sta)
-               info->control.sta = &tx->sta->sta;
-
-       return TX_CONTINUE;
-}
-
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
 {
@@ -928,7 +1010,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_supported_band *sband;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
+       int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
+                                                  NULL);
 
        sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
@@ -964,7 +1047,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                                 * because it will be recomputed and added
                                 * on transmission
                                 */
-                               if (skb->len < (iterator.max_length + FCS_LEN))
+                               if (skb->len < (iterator._max_length + FCS_LEN))
                                        return false;
 
                                skb_trim(skb, skb->len - FCS_LEN);
@@ -991,10 +1074,10 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 
        /*
         * remove the radiotap header
-        * iterator->max_length was sanity-checked against
+        * iterator->_max_length was sanity-checked against
         * skb->len by iterator init
         */
-       skb_pull(skb, iterator.max_length);
+       skb_pull(skb, iterator._max_length);
 
        return true;
 }
@@ -1016,7 +1099,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        memset(tx, 0, sizeof(*tx));
        tx->skb = skb;
-       tx->dev = sdata->dev; /* use original interface */
        tx->local = local;
        tx->sdata = sdata;
        tx->channel = local->hw.conf.channel;
@@ -1027,7 +1109,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
        tx->flags |= IEEE80211_TX_FRAGMENTED;
 
        /* process and remove the injection radiotap header */
-       if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
+       if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
                if (!__ieee80211_parse_tx_radiotap(tx, skb))
                        return TX_DROP;
 
@@ -1036,6 +1118,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                 * the radiotap header that was present and pre-filled
                 * 'tx' with tx control information.
                 */
+               info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP;
        }
 
        /*
@@ -1047,7 +1130,15 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        hdr = (struct ieee80211_hdr *) skb->data;
 
-       tx->sta = sta_info_get(local, hdr->addr1);
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+               tx->sta = rcu_dereference(sdata->u.vlan.sta);
+               if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
+                       return TX_DROP;
+       } else if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+               tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+       }
+       if (!tx->sta)
+               tx->sta = sta_info_get(sdata, hdr->addr1);
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
            (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
@@ -1199,25 +1290,34 @@ static int __ieee80211_tx(struct ieee80211_local *local,
 static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
 {
        struct sk_buff *skb = tx->skb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        ieee80211_tx_result res = TX_DROP;
 
-#define CALL_TXH(txh)          \
-       res = txh(tx);          \
-       if (res != TX_CONTINUE) \
+#define CALL_TXH(txh) \
+       do {                            \
+               res = txh(tx);          \
+               if (res != TX_CONTINUE) \
+                       goto txh_done;  \
+       } while (0)
+
+       CALL_TXH(ieee80211_tx_h_dynamic_ps);
+       CALL_TXH(ieee80211_tx_h_check_assoc);
+       CALL_TXH(ieee80211_tx_h_ps_buf);
+       CALL_TXH(ieee80211_tx_h_select_key);
+       CALL_TXH(ieee80211_tx_h_sta);
+       if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
+               CALL_TXH(ieee80211_tx_h_rate_ctrl);
+
+       if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION))
                goto txh_done;
 
-       CALL_TXH(ieee80211_tx_h_check_assoc)
-       CALL_TXH(ieee80211_tx_h_ps_buf)
-       CALL_TXH(ieee80211_tx_h_select_key)
-       CALL_TXH(ieee80211_tx_h_michael_mic_add)
-       CALL_TXH(ieee80211_tx_h_rate_ctrl)
-       CALL_TXH(ieee80211_tx_h_misc)
-       CALL_TXH(ieee80211_tx_h_sequence)
-       CALL_TXH(ieee80211_tx_h_fragment)
+       CALL_TXH(ieee80211_tx_h_michael_mic_add);
+       CALL_TXH(ieee80211_tx_h_sequence);
+       CALL_TXH(ieee80211_tx_h_fragment);
        /* handlers after fragment must be aware of tx info fragmentation! */
-       CALL_TXH(ieee80211_tx_h_stats)
-       CALL_TXH(ieee80211_tx_h_encrypt)
-       CALL_TXH(ieee80211_tx_h_calculate_duration)
+       CALL_TXH(ieee80211_tx_h_stats);
+       CALL_TXH(ieee80211_tx_h_encrypt);
+       CALL_TXH(ieee80211_tx_h_calculate_duration);
 #undef CALL_TXH
 
  txh_done:
@@ -1397,29 +1497,14 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
        int headroom;
        bool may_encrypt;
 
-       dev_hold(sdata->dev);
-
-       if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
-           local->hw.conf.dynamic_ps_timeout > 0 &&
-           !(local->scanning) && local->ps_sdata) {
-               if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-                       ieee80211_stop_queues_by_reason(&local->hw,
-                                       IEEE80211_QUEUE_STOP_REASON_PS);
-                       ieee80211_queue_work(&local->hw,
-                                       &local->dynamic_ps_disable_work);
-               }
-
-               mod_timer(&local->dynamic_ps_timer, jiffies +
-                       msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
-       }
-
-       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+       rcu_read_lock();
 
        if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
                int hdrlen;
                u16 len_rthdr;
 
-               info->flags |= IEEE80211_TX_CTL_INJECTED;
+               info->flags |= IEEE80211_TX_CTL_INJECTED |
+                              IEEE80211_TX_INTFL_HAS_RADIOTAP;
 
                len_rthdr = ieee80211_get_radiotap_len(skb->data);
                hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
@@ -1437,22 +1522,18 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                         * support we will need a different mechanism.
                         */
 
-                       rcu_read_lock();
                        list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
                                                list) {
-                               if (!netif_running(tmp_sdata->dev))
+                               if (!ieee80211_sdata_running(tmp_sdata))
                                        continue;
                                if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
                                        continue;
-                               if (compare_ether_addr(tmp_sdata->dev->dev_addr,
+                               if (compare_ether_addr(tmp_sdata->vif.addr,
                                                       hdr->addr2) == 0) {
-                                       dev_hold(tmp_sdata->dev);
-                                       dev_put(sdata->dev);
                                        sdata = tmp_sdata;
                                        break;
                                }
                        }
-                       rcu_read_unlock();
                }
        }
 
@@ -1466,7 +1547,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
        if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
                dev_kfree_skb(skb);
-               dev_put(sdata->dev);
+               rcu_read_unlock();
                return;
        }
 
@@ -1477,13 +1558,13 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                !is_multicast_ether_addr(hdr->addr1))
                        if (mesh_nexthop_lookup(skb, sdata)) {
                                /* skb queued: don't free */
-                               dev_put(sdata->dev);
+                               rcu_read_unlock();
                                return;
                        }
 
-       ieee80211_select_queue(local, skb);
+       ieee80211_set_qos_hdr(local, skb);
        ieee80211_tx(sdata, skb, false);
-       dev_put(sdata->dev);
+       rcu_read_unlock();
 }
 
 netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
@@ -1547,6 +1628,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
 
        memset(info, 0, sizeof(*info));
 
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        /* pass the radiotap header up to xmit */
        ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
        return NETDEV_TX_OK;
@@ -1585,7 +1668,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        const u8 *encaps_data;
        int encaps_len, skip_header_bytes;
        int nh_pos, h_pos;
-       struct sta_info *sta;
+       struct sta_info *sta = NULL;
        u32 sta_flags = 0;
 
        if (unlikely(skb->len < ETH_HLEN)) {
@@ -1602,12 +1685,28 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 
        switch (sdata->vif.type) {
-       case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
+               rcu_read_lock();
+               sta = rcu_dereference(sdata->u.vlan.sta);
+               if (sta) {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
+                       /* RA TA DA SA */
+                       memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
+                       memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
+                       memcpy(hdr.addr3, skb->data, ETH_ALEN);
+                       memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+                       hdrlen = 30;
+                       sta_flags = get_sta_flags(sta);
+               }
+               rcu_read_unlock();
+               if (sta)
+                       break;
+               /* fall through */
+       case NL80211_IFTYPE_AP:
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
                /* DA BSSID SA */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 24;
                break;
@@ -1615,7 +1714,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                /* RA TA DA SA */
                memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 30;
@@ -1629,8 +1728,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        goto fail;
                }
 
-               if (compare_ether_addr(dev->dev_addr,
-                                         skb->data + ETH_ALEN) == 0) {
+               if (compare_ether_addr(sdata->vif.addr,
+                                      skb->data + ETH_ALEN) == 0) {
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
                                        skb->data, skb->data + ETH_ALEN);
                        meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
@@ -1639,24 +1738,28 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        /* packet from other interface */
                        struct mesh_path *mppath;
                        int is_mesh_mcast = 1;
-                       char *mesh_da;
+                       const u8 *mesh_da;
 
                        rcu_read_lock();
                        if (is_multicast_ether_addr(skb->data))
                                /* DA TA mSA AE:SA */
                                mesh_da = skb->data;
                        else {
+                               static const u8 bcast[ETH_ALEN] =
+                                       { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
                                mppath = mpp_path_lookup(skb->data, sdata);
                                if (mppath) {
                                        /* RA TA mDA mSA AE:DA SA */
                                        mesh_da = mppath->mpp;
                                        is_mesh_mcast = 0;
-                               } else
+                               } else {
                                        /* DA TA mSA AE:SA */
-                                       mesh_da = dev->broadcast;
+                                       mesh_da = bcast;
+                               }
                        }
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
-                                       mesh_da, dev->dev_addr);
+                                       mesh_da, sdata->vif.addr);
                        rcu_read_unlock();
                        if (is_mesh_mcast)
                                meshhdrlen =
@@ -1677,12 +1780,21 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                break;
 #endif
        case NL80211_IFTYPE_STATION:
-               fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
-               /* BSSID SA DA */
                memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-               memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-               memcpy(hdr.addr3, skb->data, ETH_ALEN);
-               hdrlen = 24;
+               if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
+                       /* RA TA DA SA */
+                       memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
+                       memcpy(hdr.addr3, skb->data, ETH_ALEN);
+                       memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+                       hdrlen = 30;
+               } else {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
+                       /* BSSID SA DA */
+                       memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+                       memcpy(hdr.addr3, skb->data, ETH_ALEN);
+                       hdrlen = 24;
+               }
                break;
        case NL80211_IFTYPE_ADHOC:
                /* DA SA BSSID */
@@ -1703,9 +1815,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         */
        if (!is_multicast_ether_addr(hdr.addr1)) {
                rcu_read_lock();
-               sta = sta_info_get(local, hdr.addr1);
-               /* XXX: in the future, use sdata to look up the sta */
-               if (sta && sta->sdata == sdata)
+               sta = sta_info_get(sdata, hdr.addr1);
+               if (sta)
                        sta_flags = get_sta_flags(sta);
                rcu_read_unlock();
        }
@@ -1724,7 +1835,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                unlikely(!is_multicast_ether_addr(hdr.addr1) &&
                      !(sta_flags & WLAN_STA_AUTHORIZED) &&
                      !(ethertype == ETH_P_PAE &&
-                      compare_ether_addr(dev->dev_addr,
+                      compare_ether_addr(sdata->vif.addr,
                                          skb->data + ETH_ALEN) == 0))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit())
@@ -1864,7 +1975,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
                ieee80211_tx(sdata, skb, true);
        } else {
                hdr = (struct ieee80211_hdr *)skb->data;
-               sta = sta_info_get(local, hdr->addr1);
+               sta = sta_info_get(sdata, hdr->addr1);
 
                ret = __ieee80211_tx(local, &skb, sta, true);
                if (ret != IEEE80211_TX_OK)
@@ -1907,12 +2018,10 @@ void ieee80211_tx_pending(unsigned long data)
                        }
 
                        sdata = vif_to_sdata(info->control.vif);
-                       dev_hold(sdata->dev);
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                                flags);
 
                        txok = ieee80211_tx_pending_skb(local, skb);
-                       dev_put(sdata->dev);
                        if (!txok)
                                __skb_queue_head(&local->pending[i], skb);
                        spin_lock_irqsave(&local->queue_stop_reason_lock,
@@ -1990,8 +2099,9 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
        }
 }
 
-struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
-                                    struct ieee80211_vif *vif)
+struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
+                                        struct ieee80211_vif *vif,
+                                        u16 *tim_offset, u16 *tim_length)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct sk_buff *skb = NULL;
@@ -2001,6 +2111,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        struct beacon_data *beacon;
        struct ieee80211_supported_band *sband;
        enum ieee80211_band band = local->hw.conf.channel->band;
+       struct ieee80211_tx_rate_control txrc;
 
        sband = local->hw.wiphy->bands[band];
 
@@ -2008,6 +2119,11 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 
        sdata = vif_to_sdata(vif);
 
+       if (tim_offset)
+               *tim_offset = 0;
+       if (tim_length)
+               *tim_length = 0;
+
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                ap = &sdata->u.ap;
                beacon = rcu_dereference(ap->beacon);
@@ -2043,6 +2159,11 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                                spin_unlock_irqrestore(&local->sta_lock, flags);
                        }
 
+                       if (tim_offset)
+                               *tim_offset = beacon->head_len;
+                       if (tim_length)
+                               *tim_length = skb->len - beacon->head_len;
+
                        if (beacon->tail)
                                memcpy(skb_put(skb, beacon->tail_len),
                                       beacon->tail, beacon->tail_len);
@@ -2079,8 +2200,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                mgmt->frame_control =
                    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
                memset(mgmt->da, 0xff, ETH_ALEN);
-               memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-               /* BSSID is left zeroed, wildcard value */
+               memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
                mgmt->u.beacon.beacon_int =
                        cpu_to_le16(sdata->vif.bss_conf.beacon_int);
                mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
@@ -2098,28 +2219,160 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        info = IEEE80211_SKB_CB(skb);
 
        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       info->flags |= IEEE80211_TX_CTL_NO_ACK;
        info->band = band;
-       /*
-        * XXX: For now, always use the lowest rate
-        */
-       info->control.rates[0].idx = 0;
-       info->control.rates[0].count = 1;
-       info->control.rates[1].idx = -1;
-       info->control.rates[2].idx = -1;
-       info->control.rates[3].idx = -1;
-       info->control.rates[4].idx = -1;
-       BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
+
+       memset(&txrc, 0, sizeof(txrc));
+       txrc.hw = hw;
+       txrc.sband = sband;
+       txrc.bss_conf = &sdata->vif.bss_conf;
+       txrc.skb = skb;
+       txrc.reported_rate.idx = -1;
+       txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
+       if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
+               txrc.max_rate_idx = -1;
+       else
+               txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+       txrc.ap = true;
+       rate_control_get_rate(sdata, NULL, &txrc);
 
        info->control.vif = vif;
 
-       info->flags |= IEEE80211_TX_CTL_NO_ACK;
        info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
        info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
  out:
        rcu_read_unlock();
        return skb;
 }
-EXPORT_SYMBOL(ieee80211_beacon_get);
+EXPORT_SYMBOL(ieee80211_beacon_get_tim);
+
+struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_if_managed *ifmgd;
+       struct ieee80211_pspoll *pspoll;
+       struct ieee80211_local *local;
+       struct sk_buff *skb;
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+               return NULL;
+
+       sdata = vif_to_sdata(vif);
+       ifmgd = &sdata->u.mgd;
+       local = sdata->local;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for "
+                      "pspoll template\n", sdata->name);
+               return NULL;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
+       memset(pspoll, 0, sizeof(*pspoll));
+       pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+                                           IEEE80211_STYPE_PSPOLL);
+       pspoll->aid = cpu_to_le16(ifmgd->aid);
+
+       /* aid in PS-Poll has its two MSBs each set to 1 */
+       pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
+
+       memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
+       memcpy(pspoll->ta, vif->addr, ETH_ALEN);
+
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_pspoll_get);
+
+struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif)
+{
+       struct ieee80211_hdr_3addr *nullfunc;
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_if_managed *ifmgd;
+       struct ieee80211_local *local;
+       struct sk_buff *skb;
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+               return NULL;
+
+       sdata = vif_to_sdata(vif);
+       ifmgd = &sdata->u.mgd;
+       local = sdata->local;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc));
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+                      "template\n", sdata->name);
+               return NULL;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb,
+                                                         sizeof(*nullfunc));
+       memset(nullfunc, 0, sizeof(*nullfunc));
+       nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                             IEEE80211_STYPE_NULLFUNC |
+                                             IEEE80211_FCTL_TODS);
+       memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN);
+       memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
+       memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN);
+
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_nullfunc_get);
+
+struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      const u8 *ssid, size_t ssid_len,
+                                      const u8 *ie, size_t ie_len)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local;
+       struct ieee80211_hdr_3addr *hdr;
+       struct sk_buff *skb;
+       size_t ie_ssid_len;
+       u8 *pos;
+
+       sdata = vif_to_sdata(vif);
+       local = sdata->local;
+       ie_ssid_len = 2 + ssid_len;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) +
+                           ie_ssid_len + ie_len);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+                      "request template\n", sdata->name);
+               return NULL;
+       }
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
+       memset(hdr, 0, sizeof(*hdr));
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                        IEEE80211_STYPE_PROBE_REQ);
+       memset(hdr->addr1, 0xff, ETH_ALEN);
+       memcpy(hdr->addr2, vif->addr, ETH_ALEN);
+       memset(hdr->addr3, 0xff, ETH_ALEN);
+
+       pos = skb_put(skb, ie_ssid_len);
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = ssid_len;
+       if (ssid)
+               memcpy(pos, ssid, ssid_len);
+       pos += ssid_len;
+
+       if (ie) {
+               pos = skb_put(skb, ie_len);
+               memcpy(pos, ie, ie_len);
+       }
+
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_probereq_get);
 
 void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       const void *frame, size_t frame_len,
@@ -2214,16 +2467,14 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
 
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                     int encrypt)
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        skb_set_mac_header(skb, 0);
        skb_set_network_header(skb, 0);
        skb_set_transport_header(skb, 0);
 
-       if (!encrypt)
-               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       /* send all internal mgmt frames on VO */
+       skb_set_queue_mapping(skb, 0);
 
        /*
         * The other path calling ieee80211_xmit is from the tasklet,