MXC: mx2_defconfig file
[safe/jmp/linux-2.6] / net / mac80211 / rx.c
index 57ce697..9776f73 100644 (file)
@@ -29,6 +29,7 @@
 static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                           struct tid_ampdu_rx *tid_agg_rx,
                                           struct sk_buff *skb,
+                                          struct ieee80211_rx_status *status,
                                           u16 mpdu_seq_num,
                                           int bar_req);
 /*
@@ -86,8 +87,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
 
        if (status->flag & RX_FLAG_TSFT)
                len += 8;
-       if (local->hw.flags & IEEE80211_HW_SIGNAL_DB ||
-           local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                len += 1;
        if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
                len += 1;
@@ -143,6 +143,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        /* IEEE80211_RADIOTAP_FLAGS */
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                *pos |= IEEE80211_RADIOTAP_F_FCS;
+       if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+               *pos |= IEEE80211_RADIOTAP_F_BADFCS;
        if (status->flag & RX_FLAG_SHORTPRE)
                *pos |= IEEE80211_RADIOTAP_F_SHORTPRE;
        pos++;
@@ -158,7 +160,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                 */
                *pos = 0;
        } else {
-               rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE);
+               rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
                *pos = rate->bitrate / 5;
        }
        pos++;
@@ -199,23 +201,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        *pos = status->antenna;
        pos++;
 
-       /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
-       if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) {
-               *pos = status->signal;
-               rthdr->it_present |=
-                       cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL);
-               pos++;
-       }
-
        /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
 
        /* IEEE80211_RADIOTAP_RX_FLAGS */
        /* ensure 2 byte alignment for the 2 byte field as required */
        if ((pos - (unsigned char *)rthdr) & 1)
                pos++;
-       /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
-       if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
-               *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
+       if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
+               *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADPLCP);
        pos += 2;
 }
 
@@ -740,6 +733,39 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        return result;
 }
 
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_local *local;
+       struct ieee80211_hdr *hdr;
+       struct sk_buff *skb;
+
+       local = rx->local;
+       skb = rx->skb;
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       if (!local->pspolling)
+               return RX_CONTINUE;
+
+       if (!ieee80211_has_fromds(hdr->frame_control))
+               /* this is not from AP */
+               return RX_CONTINUE;
+
+       if (!ieee80211_is_data(hdr->frame_control))
+               return RX_CONTINUE;
+
+       if (!ieee80211_has_moredata(hdr->frame_control)) {
+               /* AP has no more frames buffered for us */
+               local->pspolling = false;
+               return RX_CONTINUE;
+       }
+
+       /* more data bit is set, let's request a new frame from the AP */
+       ieee80211_send_pspoll(local, rx->sdata);
+
+       return RX_CONTINUE;
+}
+
 static void ap_sta_ps_start(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -814,7 +840,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
                u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
                                                NL80211_IFTYPE_ADHOC);
-               if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
+               if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
                        sta->last_rx = jiffies;
        } else
        if (!is_multicast_ether_addr(hdr->addr1) ||
@@ -825,12 +851,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                 * Mesh beacons will update last_rx when if they are found to
                 * match the current local configuration when processed.
                 */
-               sta->last_rx = jiffies;
+               if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+                   ieee80211_is_beacon(hdr->frame_control)) {
+                       rx->sdata->u.mgd.last_beacon = jiffies;
+               } else
+                       sta->last_rx = jiffies;
        }
 
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
                return RX_CONTINUE;
 
+       if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
+               ieee80211_sta_rx_notify(rx->sdata, hdr);
+
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
        sta->last_signal = rx->status->signal;
@@ -1225,12 +1258,12 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 
        switch (hdr->frame_control &
                cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-       case __constant_cpu_to_le16(IEEE80211_FCTL_TODS):
+       case cpu_to_le16(IEEE80211_FCTL_TODS):
                if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
                             sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
                        return -1;
                break;
-       case __constant_cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+       case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
                if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
                             sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
                        return -1;
@@ -1244,13 +1277,13 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
                        }
                }
                break;
-       case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
+       case cpu_to_le16(IEEE80211_FCTL_FROMDS):
                if (sdata->vif.type != NL80211_IFTYPE_STATION ||
                    (is_multicast_ether_addr(dst) &&
                     !compare_ether_addr(src, dev->dev_addr)))
                        return -1;
                break;
-       case __constant_cpu_to_le16(0):
+       case cpu_to_le16(0):
                if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
                        return -1;
                break;
@@ -1364,7 +1397,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                 * mac80211. That also explains the __skb_push()
                 * below.
                 */
-               align = (unsigned long)skb->data & 4;
+               align = (unsigned long)skb->data & 3;
                if (align) {
                        if (WARN_ON(skb_headroom(skb) < 3)) {
                                dev_kfree_skb(skb);
@@ -1649,16 +1682,14 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
                start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
 
                /* reset session timer */
-               if (tid_agg_rx->timeout) {
-                       unsigned long expires =
-                               jiffies + (tid_agg_rx->timeout / 1000) * HZ;
-                       mod_timer(&tid_agg_rx->session_timer, expires);
-               }
+               if (tid_agg_rx->timeout)
+                       mod_timer(&tid_agg_rx->session_timer,
+                                 TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
                /* manage reordering buffer according to requested */
                /* sequence number */
                rcu_read_lock();
-               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
+               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL,
                                                 start_seq_num, 1);
                rcu_read_unlock();
                return RX_DROP_UNUSABLE;
@@ -1667,9 +1698,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
-                                   struct ieee80211_mgmt *mgmt,
-                                   size_t len)
+static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
+                                          struct ieee80211_mgmt *mgmt,
+                                          size_t len)
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
@@ -1680,13 +1711,13 @@ void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
-       if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 ||
-           compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) {
+       if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 ||
+           compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) {
                /* Not from the current AP. */
                return;
        }
 
-       if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) {
+       if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) {
                /* Association in progress; ignore SA Query */
                return;
        }
@@ -1705,7 +1736,7 @@ void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
        memset(resp, 0, 24);
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
        memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN);
+       memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN);
        resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
@@ -1723,7 +1754,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
        struct ieee80211_bss *bss;
        int len = rx->skb->len;
@@ -1746,6 +1776,17 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_BACK:
+               /*
+                * The aggregation code is not prepared to handle
+                * anything but STA/AP due to the BSSID handling;
+                * IBSS could work in the code but isn't supported
+                * by drivers or the standard.
+                */
+               if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+                   sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+                   sdata->vif.type != NL80211_IFTYPE_AP)
+                       return RX_DROP_MONITOR;
+
                switch (mgmt->u.action.u.addba_req.action_code) {
                case WLAN_ACTION_ADDBA_REQ:
                        if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1770,6 +1811,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
        case WLAN_CATEGORY_SPECTRUM_MGMT:
                if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
                        return RX_DROP_MONITOR;
+
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       return RX_DROP_MONITOR;
+
                switch (mgmt->u.action.u.measurement.action_code) {
                case WLAN_ACTION_SPCT_MSR_REQ:
                        if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1782,12 +1827,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                                   sizeof(mgmt->u.action.u.chan_switch)))
                                return RX_DROP_MONITOR;
 
-                       if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0)
+                       if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
                                return RX_DROP_MONITOR;
 
-                       bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+                       bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid,
                                           local->hw.conf.channel->center_freq,
-                                          ifsta->ssid, ifsta->ssid_len);
+                                          sdata->u.mgd.ssid,
+                                          sdata->u.mgd.ssid_len);
                        if (!bss)
                                return RX_DROP_MONITOR;
 
@@ -1839,15 +1885,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
        if (ieee80211_vif_is_mesh(&sdata->vif))
                return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sdata->vif.type != NL80211_IFTYPE_ADHOC)
-               return RX_DROP_MONITOR;
+       if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+               return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
 
-       if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
-               return RX_DROP_MONITOR;
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
 
-       ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
-       return RX_QUEUED;
+       return RX_DROP_MONITOR;
 }
 
 static void ieee80211_rx_michael_mic_report(struct net_device *dev,
@@ -1996,6 +2040,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
        CALL_RXH(ieee80211_rx_h_passive_scan)
        CALL_RXH(ieee80211_rx_h_check)
        CALL_RXH(ieee80211_rx_h_decrypt)
+       CALL_RXH(ieee80211_rx_h_check_more_data)
        CALL_RXH(ieee80211_rx_h_sta_process)
        CALL_RXH(ieee80211_rx_h_defragment)
        CALL_RXH(ieee80211_rx_h_ps_poll)
@@ -2039,16 +2084,17 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
 /* main receive path */
 
 static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
-                               u8 *bssid, struct ieee80211_rx_data *rx,
+                               struct ieee80211_rx_data *rx,
                                struct ieee80211_hdr *hdr)
 {
+       u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
        int multicast = is_multicast_ether_addr(hdr->addr1);
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_STATION:
                if (!bssid)
                        return 0;
-               if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+               if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) {
                        if (!(rx->flags & IEEE80211_RX_IN_SCAN))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2066,7 +2112,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                if (ieee80211_is_beacon(hdr->frame_control)) {
                        return 1;
                }
-               else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+               else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
                        if (!(rx->flags & IEEE80211_RX_IN_SCAN))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2144,7 +2190,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        int prepares;
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
-       u8 *bssid;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        memset(&rx, 0, sizeof(rx));
@@ -2183,9 +2228,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
                        continue;
 
-               bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
                rx.flags |= IEEE80211_RX_RA_MATCH;
-               prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
+               prepares = prepare_for_handlers(sdata, &rx, hdr);
 
                if (!prepares)
                        continue;
@@ -2250,6 +2294,7 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
 static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                           struct tid_ampdu_rx *tid_agg_rx,
                                           struct sk_buff *skb,
+                                          struct ieee80211_rx_status *rxstatus,
                                           u16 mpdu_seq_num,
                                           int bar_req)
 {
@@ -2331,6 +2376,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 
        /* put the frame in the reordering buffer */
        tid_agg_rx->reorder_buf[index] = skb;
+       memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
+              sizeof(*rxstatus));
        tid_agg_rx->stored_mpdu_num++;
        /* release the buffer until next missing frame */
        index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
@@ -2356,7 +2403,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 }
 
 static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
-                                    struct sk_buff *skb)
+                                    struct sk_buff *skb,
+                                    struct ieee80211_rx_status *status)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -2390,11 +2438,9 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
        /* new un-ordered ampdu frame - process it */
 
        /* reset session timer */
-       if (tid_agg_rx->timeout) {
-               unsigned long expires =
-                       jiffies + (tid_agg_rx->timeout / 1000) * HZ;
-               mod_timer(&tid_agg_rx->session_timer, expires);
-       }
+       if (tid_agg_rx->timeout)
+               mod_timer(&tid_agg_rx->session_timer,
+                         TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
        /* if this mpdu is fragmented - terminate rx aggregation session */
        sc = le16_to_cpu(hdr->seq_ctrl);
@@ -2407,7 +2453,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 
        /* according to mpdu sequence number deal with reordering buffer */
        mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
-       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
+       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status,
                                                mpdu_seq_num, 0);
  end_reorder:
        return ret;
@@ -2471,7 +2517,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                return;
        }
 
-       if (!ieee80211_rx_reorder_ampdu(local, skb))
+       if (!ieee80211_rx_reorder_ampdu(local, skb, status))
                __ieee80211_rx_handle_packet(hw, skb, status, rate);
 
        rcu_read_unlock();