mac80211: update copyrights to 2009
[safe/jmp/linux-2.6] / net / mac80211 / tx.c
index 5143d20..3ad053f 100644 (file)
@@ -317,12 +317,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)
@@ -367,12 +366,15 @@ 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)))
+       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 "
@@ -395,8 +397,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                } 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;
@@ -406,7 +413,7 @@ 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,
                       sta->sta.addr);
@@ -1044,7 +1051,10 @@ 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) && sdata->use_4addr)
+               tx->sta = rcu_dereference(sdata->u.vlan.sta);
+       if (!tx->sta)
+               tx->sta = sta_info_get(local, hdr->addr1);
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
            (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
@@ -1198,23 +1208,25 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
        struct sk_buff *skb = tx->skb;
        ieee80211_tx_result res = TX_DROP;
 
-#define CALL_TXH(txh)          \
-       res = txh(tx);          \
-       if (res != TX_CONTINUE) \
-               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)
+#define CALL_TXH(txh) \
+       do {                            \
+               res = txh(tx);          \
+               if (res != TX_CONTINUE) \
+                       goto txh_done;  \
+       } while (0)
+
+       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);
        /* 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:
@@ -1384,6 +1396,30 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
        return 0;
 }
 
+static bool need_dynamic_ps(struct ieee80211_local *local)
+{
+       /* driver doesn't support power save */
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+               return false;
+
+       /* hardware does dynamic power save */
+       if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+               return false;
+
+       /* dynamic power save disabled */
+       if (local->hw.conf.dynamic_ps_timeout <= 0)
+               return false;
+
+       /* we are scanning, don't enable power save */
+       if (local->scanning)
+               return false;
+
+       if (!local->ps_sdata)
+               return false;
+
+       return true;
+}
+
 static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                           struct sk_buff *skb)
 {
@@ -1396,9 +1432,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
        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 (need_dynamic_ps(local)) {
                if (local->hw.conf.flags & IEEE80211_CONF_PS) {
                        ieee80211_stop_queues_by_reason(&local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_PS);
@@ -1442,7 +1476,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                                if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
                                        continue;
                                if (compare_ether_addr(tmp_sdata->dev->dev_addr,
-                                                      hdr->addr2)) {
+                                                      hdr->addr2) == 0) {
                                        dev_hold(tmp_sdata->dev);
                                        dev_put(sdata->dev);
                                        sdata = tmp_sdata;
@@ -1582,7 +1616,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)) {
@@ -1599,8 +1633,25 @@ 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();
+               if (sdata->use_4addr)
+                       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, dev->dev_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);
@@ -1674,12 +1725,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->use_4addr && ethertype != ETH_P_PAE) {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
+                       /* RA TA DA SA */
+                       memcpy(hdr.addr2, dev->dev_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 */
@@ -1701,7 +1761,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);
-               if (sta)
+               /* XXX: in the future, use sdata to look up the sta */
+               if (sta && sta->sdata == sdata)
                        sta_flags = get_sta_flags(sta);
                rcu_read_unlock();
        }
@@ -1986,8 +2047,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;
@@ -2004,6 +2066,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);
@@ -2039,6 +2106,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);
@@ -2076,7 +2148,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                    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->bssid, sdata->dev->dev_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 */
@@ -2115,7 +2187,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        rcu_read_unlock();
        return skb;
 }
-EXPORT_SYMBOL(ieee80211_beacon_get);
+EXPORT_SYMBOL(ieee80211_beacon_get_tim);
 
 void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       const void *frame, size_t frame_len,