]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/mac80211/rx.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux.git] / net / mac80211 / rx.c
index 9dce3b157908b3d229fb293a8f5acbce9057ea63..b791c41905640e0352602c38998a9adf8f79b3ab 100644 (file)
@@ -180,6 +180,11 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
                len += 12;
        }
 
+       if (local->hw.radiotap_timestamp.units_pos >= 0) {
+               len = ALIGN(len, 8);
+               len += 12;
+       }
+
        if (status->chains) {
                /* antenna and antenna signal fields */
                len += 2 * hweight8(status->chains);
@@ -447,6 +452,31 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                pos += 2;
        }
 
+       if (local->hw.radiotap_timestamp.units_pos >= 0) {
+               u16 accuracy = 0;
+               u8 flags = IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT;
+
+               rthdr->it_present |=
+                       cpu_to_le32(1 << IEEE80211_RADIOTAP_TIMESTAMP);
+
+               /* ensure 8 byte alignment */
+               while ((pos - (u8 *)rthdr) & 7)
+                       pos++;
+
+               put_unaligned_le64(status->device_timestamp, pos);
+               pos += sizeof(u64);
+
+               if (local->hw.radiotap_timestamp.accuracy >= 0) {
+                       accuracy = local->hw.radiotap_timestamp.accuracy;
+                       flags |= IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY;
+               }
+               put_unaligned_le16(accuracy, pos);
+               pos += sizeof(u16);
+
+               *pos++ = local->hw.radiotap_timestamp.units_pos;
+               *pos++ = flags;
+       }
+
        for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
                *pos++ = status->chain_signal[chain];
                *pos++ = chain;
@@ -485,6 +515,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        struct net_device *prev_dev = NULL;
        int present_fcs_len = 0;
        unsigned int rtap_vendor_space = 0;
+       struct ieee80211_mgmt *mgmt;
+       struct ieee80211_sub_if_data *monitor_sdata =
+               rcu_dereference(local->monitor_sdata);
 
        if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) {
                struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data;
@@ -567,7 +600,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
                        continue;
 
-               if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
+               if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
                        continue;
 
                if (!ieee80211_sdata_running(sdata))
@@ -585,6 +618,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                ieee80211_rx_stats(sdata->dev, skb->len);
        }
 
+       mgmt = (void *)skb->data;
+       if (monitor_sdata &&
+           skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + VHT_MUMIMO_GROUPS_DATA_LEN &&
+           ieee80211_is_action(mgmt->frame_control) &&
+           mgmt->u.action.category == WLAN_CATEGORY_VHT &&
+           mgmt->u.action.u.vht_group_notif.action_code == WLAN_VHT_ACTION_GROUPID_MGMT &&
+           is_valid_ether_addr(monitor_sdata->u.mntr.mu_follow_addr) &&
+           ether_addr_equal(mgmt->da, monitor_sdata->u.mntr.mu_follow_addr)) {
+               struct sk_buff *mu_skb = skb_copy(skb, GFP_ATOMIC);
+
+               if (mu_skb) {
+                       mu_skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+                       skb_queue_tail(&monitor_sdata->skb_queue, mu_skb);
+                       ieee80211_queue_work(&local->hw, &monitor_sdata->work);
+               }
+       }
+
        if (prev_dev) {
                skb->dev = prev_dev;
                netif_receive_skb(skb);
@@ -1072,8 +1122,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
-       if (!tid_agg_rx)
+       if (!tid_agg_rx) {
+               if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+                   !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
+                   !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
+                       ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
+                                            WLAN_BACK_RECIPIENT,
+                                            WLAN_REASON_QSTA_REQUIRE_SETUP);
                goto dont_reorder;
+       }
 
        /* qos null data frames are excluded */
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
@@ -1266,9 +1323,7 @@ static void sta_ps_start(struct sta_info *sta)
                return;
 
        for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
-               struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
-
-               if (txqi->tin.backlog_packets)
+               if (txq_has_queue(sta->sta.txq[tid]))
                        set_bit(tid, &sta->txq_buffered_tids);
                else
                        clear_bit(tid, &sta->txq_buffered_tids);
@@ -1339,13 +1394,15 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
        u8 ac = ieee802_1d_to_ac[tid & 7];
 
        /*
-        * If this AC is not trigger-enabled do nothing.
+        * If this AC is not trigger-enabled do nothing unless the
+        * driver is calling us after it already checked.
         *
         * NB: This could/should check a separate bitmap of trigger-
         * enabled queues, but for now we only implement uAPSD w/o
         * TSPEC changes to the ACs, so they're always the same.
         */
-       if (!(sta->sta.uapsd_queues & BIT(ac)))
+       if (!(sta->sta.uapsd_queues & ieee80211_ac_to_qos_mask[ac]) &&
+           tid != IEEE80211_NUM_TIDS)
                return;
 
        /* if we are in a service period, do nothing */
@@ -1851,7 +1908,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        unsigned int frag, seq;
        struct ieee80211_fragment_entry *entry;
        struct sk_buff *skb;
-       struct ieee80211_rx_status *status;
 
        hdr = (struct ieee80211_hdr *)rx->skb->data;
        fc = hdr->frame_control;
@@ -1977,9 +2033,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                dev_kfree_skb(skb);
        }
 
-       /* Complete frame has been reassembled - process it now */
-       status = IEEE80211_SKB_RXCB(rx->skb);
-
  out:
        ieee80211_led_rx(rx->local);
  out_no_led:
@@ -2160,7 +2213,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
             sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
            !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
            (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
-               if (is_multicast_ether_addr(ehdr->h_dest)) {
+               if (is_multicast_ether_addr(ehdr->h_dest) &&
+                   ieee80211_vif_get_num_mcast_if(sdata) != 0) {
                        /*
                         * send multicast frames both to higher layers in
                         * local net stack and back to the wireless medium
@@ -2169,7 +2223,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                        if (!xmit_skb)
                                net_info_ratelimited("%s: failed to clone multicast frame\n",
                                                    dev->name);
-               } else {
+               } else if (!is_multicast_ether_addr(ehdr->h_dest)) {
                        dsta = sta_info_get(sdata, skb->data);
                        if (dsta) {
                                /*
@@ -2243,6 +2297,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        __le16 fc = hdr->frame_control;
        struct sk_buff_head frame_list;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       struct ethhdr ethhdr;
+       const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
 
        if (unlikely(!ieee80211_is_data(fc)))
                return RX_CONTINUE;
@@ -2253,24 +2309,53 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (!(status->rx_flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
-       if (ieee80211_has_a4(hdr->frame_control) &&
-           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-           !rx->sdata->u.vlan.sta)
-               return RX_DROP_UNUSABLE;
+       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
+               switch (rx->sdata->vif.type) {
+               case NL80211_IFTYPE_AP_VLAN:
+                       if (!rx->sdata->u.vlan.sta)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       if (!rx->sdata->u.mgd.use_4addr)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               default:
+                       return RX_DROP_UNUSABLE;
+               }
+               check_da = NULL;
+               check_sa = NULL;
+       } else switch (rx->sdata->vif.type) {
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
+                       check_da = NULL;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       if (!rx->sta ||
+                           !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
+                               check_sa = NULL;
+                       break;
+               case NL80211_IFTYPE_MESH_POINT:
+                       check_sa = NULL;
+                       break;
+               default:
+                       break;
+       }
 
-       if (is_multicast_ether_addr(hdr->addr1) &&
-           ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-             rx->sdata->u.vlan.sta) ||
-            (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
-             rx->sdata->u.mgd.use_4addr)))
+       if (is_multicast_ether_addr(hdr->addr1))
                return RX_DROP_UNUSABLE;
 
        skb->dev = dev;
        __skb_queue_head_init(&frame_list);
 
+       if (ieee80211_data_to_8023_exthdr(skb, &ethhdr,
+                                         rx->sdata->vif.addr,
+                                         rx->sdata->vif.type))
+               return RX_DROP_UNUSABLE;
+
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
-                                rx->local->hw.extra_tx_headroom, true);
+                                rx->local->hw.extra_tx_headroom,
+                                check_da, check_sa);
 
        while (!skb_queue_empty(&frame_list)) {
                rx->skb = __skb_dequeue(&frame_list);
@@ -2383,7 +2468,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        if (!ifmsh->mshcfg.dot11MeshForwarding)
                goto out;
 
-       fwd_skb = skb_copy(skb, GFP_ATOMIC);
+       fwd_skb = skb_copy_expand(skb, local->tx_headroom +
+                                      sdata->encrypt_headroom, 0, GFP_ATOMIC);
        if (!fwd_skb) {
                net_info_ratelimited("%s: failed to clone mesh frame\n",
                                    sdata->name);
@@ -2535,6 +2621,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
 
                tid = le16_to_cpu(bar_data.control) >> 12;
 
+               if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
+                   !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
+                       ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
+                                            WLAN_BACK_RECIPIENT,
+                                            WLAN_REASON_QSTA_REQUIRE_SETUP);
+
                tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
                if (!tid_agg_rx)
                        return RX_DROP_MONITOR;
@@ -2785,17 +2877,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
                switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
                case WLAN_VHT_ACTION_OPMODE_NOTIF: {
-                       u8 opmode;
-
                        /* verify opmode is present */
                        if (len < IEEE80211_MIN_ACTION_SIZE + 2)
                                goto invalid;
-
-                       opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
-
-                       ieee80211_vht_handle_opmode(rx->sdata, rx->sta,
-                                                   opmode, status->band);
-                       goto handled;
+                       goto queue;
                }
                case WLAN_VHT_ACTION_GROUPID_MGMT: {
                        if (len < IEEE80211_MIN_ACTION_SIZE + 25)
@@ -3147,7 +3232,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                        continue;
 
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
-                   !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+                   !(sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES))
                        continue;
 
                if (prev_dev) {
@@ -3523,6 +3608,9 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
                       ieee80211_is_probe_req(hdr->frame_control) ||
                       ieee80211_is_probe_resp(hdr->frame_control) ||
                       ieee80211_is_beacon(hdr->frame_control);
+       case NL80211_IFTYPE_NAN:
+               /* Currently no frames on NAN interface are allowed */
+               return false;
        default:
                break;
        }
@@ -3844,21 +3932,31 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
        u64_stats_update_end(&stats->syncp);
 
        if (fast_rx->internal_forward) {
-               struct sta_info *dsta = sta_info_get(rx->sdata, skb->data);
+               struct sk_buff *xmit_skb = NULL;
+               bool multicast = is_multicast_ether_addr(skb->data);
+
+               if (multicast) {
+                       xmit_skb = skb_copy(skb, GFP_ATOMIC);
+               } else if (sta_info_get(rx->sdata, skb->data)) {
+                       xmit_skb = skb;
+                       skb = NULL;
+               }
 
-               if (dsta) {
+               if (xmit_skb) {
                        /*
                         * Send to wireless media and increase priority by 256
                         * to keep the received priority instead of
                         * reclassifying the frame (see cfg80211_classify8021d).
                         */
-                       skb->priority += 256;
-                       skb->protocol = htons(ETH_P_802_3);
-                       skb_reset_network_header(skb);
-                       skb_reset_mac_header(skb);
-                       dev_queue_xmit(skb);
-                       return true;
+                       xmit_skb->priority += 256;
+                       xmit_skb->protocol = htons(ETH_P_802_3);
+                       skb_reset_network_header(xmit_skb);
+                       skb_reset_mac_header(xmit_skb);
+                       dev_queue_xmit(xmit_skb);
                }
+
+               if (!skb)
+                       return true;
        }
 
        /* deliver to local stack */
@@ -3940,7 +4038,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        __le16 fc;
        struct ieee80211_rx_data rx;
        struct ieee80211_sub_if_data *prev;
-       struct rhash_head *tmp;
+       struct rhlist_head *tmp;
        int err = 0;
 
        fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
@@ -3983,13 +4081,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                goto out;
        } else if (ieee80211_is_data(fc)) {
                struct sta_info *sta, *prev_sta;
-               const struct bucket_table *tbl;
 
                prev_sta = NULL;
 
-               tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
-
-               for_each_sta_info(local, tbl, hdr->addr2, sta, tmp) {
+               for_each_sta_info(local, hdr->addr2, sta, tmp) {
                        if (!prev_sta) {
                                prev_sta = sta;
                                continue;