]> Pileus Git - ~andy/linux/blobdiff - net/mac80211/rx.c
mac80211: in ADHOC don't update last_rx if sta is not authorized
[~andy/linux] / net / mac80211 / rx.c
index 61c621e9273fe70c26978d42433d58fca60a80b8..b2ae2baefc9a3673ec51eb8e0c0f7486dca0d890 100644 (file)
@@ -40,6 +40,8 @@
 static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
                                           struct sk_buff *skb)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
                if (likely(skb->len > FCS_LEN))
                        __pskb_trim(skb, skb->len - FCS_LEN);
@@ -51,20 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
                }
        }
 
+       if (status->vendor_radiotap_len)
+               __pskb_pull(skb, status->vendor_radiotap_len);
+
        return skb;
 }
 
-static inline int should_drop_frame(struct sk_buff *skb,
-                                   int present_fcs_len)
+static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len)
 {
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_hdr *hdr;
+
+       hdr = (void *)(skb->data + status->vendor_radiotap_len);
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
                            RX_FLAG_FAILED_PLCP_CRC |
                            RX_FLAG_AMPDU_IS_ZEROLEN))
                return 1;
-       if (unlikely(skb->len < 16 + present_fcs_len))
+       if (unlikely(skb->len < 16 + present_fcs_len +
+                               status->vendor_radiotap_len))
                return 1;
        if (ieee80211_is_ctl(hdr->frame_control) &&
            !ieee80211_is_pspoll(hdr->frame_control) &&
@@ -74,32 +81,48 @@ static inline int should_drop_frame(struct sk_buff *skb,
 }
 
 static int
-ieee80211_rx_radiotap_len(struct ieee80211_local *local,
-                         struct ieee80211_rx_status *status)
+ieee80211_rx_radiotap_space(struct ieee80211_local *local,
+                           struct ieee80211_rx_status *status)
 {
        int len;
 
        /* always present fields */
        len = sizeof(struct ieee80211_radiotap_header) + 9;
 
-       if (status->flag & RX_FLAG_MACTIME_MPDU)
+       /* allocate extra bitmap */
+       if (status->vendor_radiotap_len)
+               len += 4;
+
+       if (ieee80211_have_rx_timestamp(status)) {
+               len = ALIGN(len, 8);
                len += 8;
+       }
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                len += 1;
 
-       if (len & 1) /* padding for RX_FLAGS if necessary */
-               len++;
+       /* padding for RX_FLAGS if necessary */
+       len = ALIGN(len, 2);
 
        if (status->flag & RX_FLAG_HT) /* HT info */
                len += 3;
 
        if (status->flag & RX_FLAG_AMPDU_DETAILS) {
-               /* padding */
-               while (len & 3)
-                       len++;
+               len = ALIGN(len, 4);
                len += 8;
        }
 
+       if (status->vendor_radiotap_len) {
+               if (WARN_ON_ONCE(status->vendor_radiotap_align == 0))
+                       status->vendor_radiotap_align = 1;
+               /* align standard part of vendor namespace */
+               len = ALIGN(len, 2);
+               /* allocate standard part of vendor namespace */
+               len += 6;
+               /* align vendor-defined part */
+               len = ALIGN(len, status->vendor_radiotap_align);
+               /* vendor-defined part is already in skb */
+       }
+
        return len;
 }
 
@@ -118,6 +141,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        struct ieee80211_radiotap_header *rthdr;
        unsigned char *pos;
        u16 rx_flags = 0;
+       int mpdulen;
+
+       mpdulen = skb->len;
+       if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)))
+               mpdulen += FCS_LEN;
 
        rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
        memset(rthdr, 0, rtap_len);
@@ -128,17 +156,30 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                            (1 << IEEE80211_RADIOTAP_CHANNEL) |
                            (1 << IEEE80211_RADIOTAP_ANTENNA) |
                            (1 << IEEE80211_RADIOTAP_RX_FLAGS));
-       rthdr->it_len = cpu_to_le16(rtap_len);
+       rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len);
 
-       pos = (unsigned char *)(rthdr+1);
+       pos = (unsigned char *)(rthdr + 1);
+
+       if (status->vendor_radiotap_len) {
+               rthdr->it_present |=
+                       cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) |
+                       cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT));
+               put_unaligned_le32(status->vendor_radiotap_bitmap, pos);
+               pos += 4;
+       }
 
        /* the order of the following fields is important */
 
        /* IEEE80211_RADIOTAP_TSFT */
-       if (status->flag & RX_FLAG_MACTIME_MPDU) {
-               put_unaligned_le64(status->mactime, pos);
-               rthdr->it_present |=
-                       cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+       if (ieee80211_have_rx_timestamp(status)) {
+               /* padding */
+               while ((pos - (u8 *)rthdr) & 7)
+                       *pos++ = 0;
+               put_unaligned_le64(
+                       ieee80211_calculate_rx_timestamp(local, status,
+                                                        mpdulen, 0),
+                       pos);
+               rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
                pos += 8;
        }
 
@@ -205,7 +246,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        /* IEEE80211_RADIOTAP_RX_FLAGS */
        /* ensure 2 byte alignment for the 2 byte field as required */
        if ((pos - (u8 *)rthdr) & 1)
-               pos++;
+               *pos++ = 0;
        if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
                rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
        put_unaligned_le16(rx_flags, pos);
@@ -255,6 +296,21 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                        *pos++ = 0;
                *pos++ = 0;
        }
+
+       if (status->vendor_radiotap_len) {
+               /* ensure 2 byte alignment for the vendor field as required */
+               if ((pos - (u8 *)rthdr) & 1)
+                       *pos++ = 0;
+               *pos++ = status->vendor_radiotap_oui[0];
+               *pos++ = status->vendor_radiotap_oui[1];
+               *pos++ = status->vendor_radiotap_oui[2];
+               *pos++ = status->vendor_radiotap_subns;
+               put_unaligned_le16(status->vendor_radiotap_len, pos);
+               pos += 2;
+               /* align the actual payload as requested */
+               while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1))
+                       *pos++ = 0;
+       }
 }
 
 /*
@@ -283,13 +339,13 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
         */
 
        /* room for the radiotap header based on driver features */
-       needed_headroom = ieee80211_rx_radiotap_len(local, status);
+       needed_headroom = ieee80211_rx_radiotap_space(local, status);
 
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
 
-       /* make sure hdr->frame_control is on the linear part */
-       if (!pskb_may_pull(origskb, 2)) {
+       /* ensure hdr->frame_control and vendor radiotap data are in skb head */
+       if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) {
                dev_kfree_skb(origskb);
                return NULL;
        }
@@ -374,7 +430,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        return origskb;
 }
 
-
 static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@@ -403,10 +458,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
                 *
                 * We also use that counter for non-QoS STAs.
                 */
-               seqno_idx = NUM_RX_DATA_QUEUES;
+               seqno_idx = IEEE80211_NUM_TIDS;
                security_idx = 0;
                if (ieee80211_is_mgmt(hdr->frame_control))
-                       security_idx = NUM_RX_DATA_QUEUES;
+                       security_idx = IEEE80211_NUM_TIDS;
                tid = 0;
        }
 
@@ -481,8 +536,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
        struct ieee80211_mmie *mmie;
 
-       if (skb->len < 24 + sizeof(*mmie) ||
-           !is_multicast_ether_addr(hdr->da))
+       if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
                return -1;
 
        if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
@@ -497,9 +551,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        return le16_to_cpu(mmie->key_id);
 }
 
-
-static ieee80211_rx_result
-ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        char *dev_addr = rx->sdata->vif.addr;
@@ -507,7 +559,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
        if (ieee80211_is_data(hdr->frame_control)) {
                if (is_multicast_ether_addr(hdr->addr1)) {
                        if (ieee80211_has_tods(hdr->frame_control) ||
-                               !ieee80211_has_fromds(hdr->frame_control))
+                           !ieee80211_has_fromds(hdr->frame_control))
                                return RX_DROP_MONITOR;
                        if (ether_addr_equal(hdr->addr3, dev_addr))
                                return RX_DROP_MONITOR;
@@ -531,10 +583,15 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
                if (ieee80211_is_action(hdr->frame_control)) {
                        u8 category;
+
+                       /* make sure category field is present */
+                       if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
+                               return RX_DROP_MONITOR;
+
                        mgmt = (struct ieee80211_mgmt *)hdr;
                        category = mgmt->u.action.category;
                        if (category != WLAN_CATEGORY_MESH_ACTION &&
-                               category != WLAN_CATEGORY_SELF_PROTECTED)
+                           category != WLAN_CATEGORY_SELF_PROTECTED)
                                return RX_DROP_MONITOR;
                        return RX_CONTINUE;
                }
@@ -546,7 +603,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
                        return RX_CONTINUE;
 
                return RX_DROP_MONITOR;
-
        }
 
        return RX_CONTINUE;
@@ -570,7 +626,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
        return (sq1 - sq2) & SEQ_MASK;
 }
 
-
 static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
                                            struct tid_ampdu_rx *tid_agg_rx,
                                            int index)
@@ -883,14 +938,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                 */
                if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
                    ieee80211_is_data_present(hdr->frame_control)) {
-                       u16 ethertype;
-                       u8 *payload;
-
-                       payload = rx->skb->data +
-                               ieee80211_hdrlen(hdr->frame_control);
-                       ethertype = (payload[6] << 8) | payload[7];
-                       if (cpu_to_be16(ethertype) ==
-                           rx->sdata->control_port_protocol)
+                       unsigned int hdrlen;
+                       __be16 ethertype;
+
+                       hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+                       if (rx->skb->len < hdrlen + 8)
+                               return RX_DROP_MONITOR;
+
+                       skb_copy_bits(rx->skb, hdrlen + 6, &ethertype, 2);
+                       if (ethertype == rx->sdata->control_port_protocol)
                                return RX_CONTINUE;
                }
 
@@ -1141,12 +1198,19 @@ ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-static void ap_sta_ps_start(struct sta_info *sta)
+static void sta_ps_start(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
+       struct ps_data *ps;
 
-       atomic_inc(&sdata->bss->num_sta_ps);
+       if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
+           sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               ps = &sdata->bss->ps;
+       else
+               return;
+
+       atomic_inc(&ps->num_sta_ps);
        set_sta_flag(sta, WLAN_STA_PS_STA);
        if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
                drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
@@ -1154,7 +1218,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
               sta->sta.addr, sta->sta.aid);
 }
 
-static void ap_sta_ps_end(struct sta_info *sta)
+static void sta_ps_end(struct sta_info *sta)
 {
        ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
               sta->sta.addr, sta->sta.aid);
@@ -1181,9 +1245,9 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
                return -EINVAL;
 
        if (start)
-               ap_sta_ps_start(sta_inf);
+               sta_ps_start(sta_inf);
        else
-               ap_sta_ps_end(sta_inf);
+               sta_ps_end(sta_inf);
 
        return 0;
 }
@@ -1277,13 +1341,17 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
        /*
         * Update last_rx only for IBSS packets which are for the current
-        * BSSID to avoid keeping the current IBSS network alive in cases
-        * where other STAs start using different BSSID.
+        * BSSID and for station already AUTHORIZED to avoid keeping the
+        * current IBSS network alive in cases where other STAs start
+        * using different BSSID. This will also give the station another
+        * chance to restart the authentication/authorization in case
+        * something went wrong the first time.
         */
        if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
                u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
                                                NL80211_IFTYPE_ADHOC);
-               if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid)) {
+               if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
+                   test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
                        sta->last_rx = jiffies;
                        if (ieee80211_is_data(hdr->frame_control)) {
                                sta->last_rx_rate_idx = status->rate_idx;
@@ -1335,10 +1403,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                         */
                        if (ieee80211_is_data(hdr->frame_control) &&
                            !ieee80211_has_pm(hdr->frame_control))
-                               ap_sta_ps_end(sta);
+                               sta_ps_end(sta);
                } else {
                        if (ieee80211_has_pm(hdr->frame_control))
-                               ap_sta_ps_start(sta);
+                               sta_ps_start(sta);
                }
        }
 
@@ -1384,9 +1452,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
                         struct sk_buff **skb)
 {
        struct ieee80211_fragment_entry *entry;
-       int idx;
 
-       idx = sdata->fragment_next;
        entry = &sdata->fragments[sdata->fragment_next++];
        if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
                sdata->fragment_next = 0;
@@ -1462,11 +1528,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 
        hdr = (struct ieee80211_hdr *)rx->skb->data;
        fc = hdr->frame_control;
+
+       if (ieee80211_is_ctl(fc))
+               return RX_CONTINUE;
+
        sc = le16_to_cpu(hdr->seq_ctrl);
        frag = sc & IEEE80211_SCTL_FRAG;
 
        if (likely((!ieee80211_has_morefrags(fc) && frag == 0) ||
-                  (rx->skb)->len < 24 ||
                   is_multicast_ether_addr(hdr->addr1))) {
                /* not fragmented */
                goto out;
@@ -1570,18 +1639,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-static int
-ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
+static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 {
-       if (unlikely(!rx->sta ||
-           !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
+       if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
                return -EACCES;
 
        return 0;
 }
 
-static int
-ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
+static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 {
        struct sk_buff *skb = rx->skb;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@@ -1603,8 +1669,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
        return 0;
 }
 
-static int
-ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
+static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
@@ -1889,6 +1954,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+       /* make sure fixed part of mesh header is there, also checks skb len */
+       if (!pskb_may_pull(rx->skb, hdrlen + 6))
+               return RX_DROP_MONITOR;
+
+       mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+
+       /* make sure full mesh header is there, also checks skb len */
+       if (!pskb_may_pull(rx->skb,
+                          hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
+               return RX_DROP_MONITOR;
+
+       /* reload pointers */
+       hdr = (struct ieee80211_hdr *) skb->data;
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
 
        /* frame is in RMC, don't forward */
@@ -1897,7 +1976,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
                return RX_DROP_MONITOR;
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (!ieee80211_is_data(hdr->frame_control) ||
+           !(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_CONTINUE;
 
        if (!mesh_hdr->ttl)
@@ -1911,9 +1991,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                if (is_multicast_ether_addr(hdr->addr1)) {
                        mpp_addr = hdr->addr3;
                        proxied_addr = mesh_hdr->eaddr1;
-               } else {
+               } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) {
+                       /* has_a4 already checked in ieee80211_rx_mesh_check */
                        mpp_addr = hdr->addr4;
                        proxied_addr = mesh_hdr->eaddr2;
+               } else {
+                       return RX_DROP_MONITOR;
                }
 
                rcu_read_lock();
@@ -1941,12 +2024,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        }
        skb_set_queue_mapping(skb, q);
 
-       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-               goto out;
-
        if (!--mesh_hdr->ttl) {
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
-               return RX_DROP_MONITOR;
+               goto out;
        }
 
        if (!ifmsh->mshcfg.dot11MeshForwarding)
@@ -1973,7 +2053,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        } else {
                /* unable to resolve next hop */
                mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
-                                   0, reason, fwd_hdr->addr2, sdata);
+                                  0, reason, fwd_hdr->addr2, sdata);
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
                kfree_skb(fwd_skb);
                return RX_DROP_MONITOR;
@@ -2182,7 +2262,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
 
                cfg80211_report_obss_beacon(rx->local->hw.wiphy,
                                            rx->skb->data, rx->skb->len,
-                                           status->freq, sig, GFP_ATOMIC);
+                                           status->freq, sig);
                rx->flags |= IEEE80211_RX_BEACON_REPORTED;
        }
 
@@ -2353,6 +2433,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
                break;
        case WLAN_CATEGORY_SELF_PROTECTED:
+               if (len < (IEEE80211_MIN_ACTION_SIZE +
+                          sizeof(mgmt->u.action.u.self_prot.action_code)))
+                       break;
+
                switch (mgmt->u.action.u.self_prot.action_code) {
                case WLAN_SP_MESH_PEERING_OPEN:
                case WLAN_SP_MESH_PEERING_CLOSE:
@@ -2371,10 +2455,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
                break;
        case WLAN_CATEGORY_MESH_ACTION:
+               if (len < (IEEE80211_MIN_ACTION_SIZE +
+                          sizeof(mgmt->u.action.u.mesh_action.action_code)))
+                       break;
+
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
                if (mesh_action_is_path_sel(mgmt) &&
-                 (!mesh_path_sel_is_hwmp(sdata)))
+                   !mesh_path_sel_is_hwmp(sdata))
                        break;
                goto queue;
        }
@@ -2430,7 +2518,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
                return RX_QUEUED;
        }
 
-
        return RX_CONTINUE;
 }
 
@@ -2560,7 +2647,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                goto out_free_skb;
 
        /* room for the radiotap header based on driver features */
-       needed_headroom = ieee80211_rx_radiotap_len(local, status);
+       needed_headroom = ieee80211_rx_radiotap_space(local, status);
 
        if (skb_headroom(skb) < needed_headroom &&
            pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
@@ -2913,10 +3000,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
                local->dot11ReceivedFragmentCount++;
 
-       if (ieee80211_is_mgmt(fc))
-               err = skb_linearize(skb);
-       else
+       if (ieee80211_is_mgmt(fc)) {
+               /* drop frame if too short for header */
+               if (skb->len < ieee80211_hdrlen(fc))
+                       err = -ENOBUFS;
+               else
+                       err = skb_linearize(skb);
+       } else {
                err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
+       }
 
        if (err) {
                dev_kfree_skb(skb);
@@ -3010,8 +3102,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        WARN_ON_ONCE(softirq_count() == 0);
 
-       if (WARN_ON(status->band < 0 ||
-                   status->band >= IEEE80211_NUM_BANDS))
+       if (WARN_ON(status->band >= IEEE80211_NUM_BANDS))
                goto drop;
 
        sband = local->hw.wiphy->bands[status->band];
@@ -3056,8 +3147,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                         * hardware error. The driver should catch hardware
                         * errors.
                         */
-                       if (WARN((status->rate_idx < 0 ||
-                                status->rate_idx > 76),
+                       if (WARN(status->rate_idx > 76,
                                 "Rate marked as an HT rate but passed "
                                 "status->rate_idx is not "
                                 "an MCS index [0-76]: %d (0x%02x)\n",
@@ -3065,8 +3155,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                                 status->rate_idx))
                                goto drop;
                } else {
-                       if (WARN_ON(status->rate_idx < 0 ||
-                                   status->rate_idx >= sband->n_bitrates))
+                       if (WARN_ON(status->rate_idx >= sband->n_bitrates))
                                goto drop;
                        rate = &sband->bitrates[status->rate_idx];
                }