mac80211: split off mesh handling entirely
[safe/jmp/linux-2.6] / net / mac80211 / rx.c
index 2464263..208563a 100644 (file)
@@ -404,11 +404,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
        struct sk_buff *skb = rx->skb;
 
        if (unlikely(local->sta_hw_scanning))
-               return ieee80211_sta_rx_scan(rx->dev, skb, rx->status);
+               return ieee80211_sta_rx_scan(rx->sdata, skb, rx->status);
 
        if (unlikely(local->sta_sw_scanning)) {
                /* drop all the other packets during a software scan anyway */
-               if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status)
+               if (ieee80211_sta_rx_scan(rx->sdata, skb, rx->status)
                    != RX_QUEUED)
                        dev_kfree_skb(skb);
                return RX_QUEUED;
@@ -466,7 +466,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
-           mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
+           mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata))
                return RX_DROP_MONITOR;
 #undef msh_h_get
 
@@ -1404,7 +1404,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        if (rx->flags & IEEE80211_RX_RA_MATCH) {
                if (!mesh_hdr->ttl)
-                       IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.sta,
+                       IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
                                                     dropped_frames_ttl);
                else {
                        struct ieee80211_hdr *fwd_hdr;
@@ -1511,22 +1511,97 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 }
 
 static ieee80211_rx_result debug_noinline
+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_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+       int len = rx->skb->len;
+
+       if (!ieee80211_is_action(mgmt->frame_control))
+               return RX_CONTINUE;
+
+       if (!rx->sta)
+               return RX_DROP_MONITOR;
+
+       if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+               return RX_DROP_MONITOR;
+
+       /* all categories we currently handle have action_code */
+       if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+               return RX_DROP_MONITOR;
+
+       /*
+        * FIXME: revisit this, I'm sure we should handle most
+        *        of these frames in other modes as well!
+        */
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
+               return RX_DROP_MONITOR;
+
+       switch (mgmt->u.action.category) {
+       case WLAN_CATEGORY_BACK:
+               switch (mgmt->u.action.u.addba_req.action_code) {
+               case WLAN_ACTION_ADDBA_REQ:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.addba_req)))
+                               return RX_DROP_MONITOR;
+                       ieee80211_process_addba_request(local, rx->sta, mgmt, len);
+                       break;
+               case WLAN_ACTION_ADDBA_RESP:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.addba_resp)))
+                               return RX_DROP_MONITOR;
+                       ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
+                       break;
+               case WLAN_ACTION_DELBA:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.delba)))
+                               return RX_DROP_MONITOR;
+                       ieee80211_process_delba(sdata, rx->sta, mgmt, len);
+                       break;
+               }
+               break;
+       case WLAN_CATEGORY_SPECTRUM_MGMT:
+               if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
+                       return RX_DROP_MONITOR;
+               switch (mgmt->u.action.u.measurement.action_code) {
+               case WLAN_ACTION_SPCT_MSR_REQ:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.measurement)))
+                               return RX_DROP_MONITOR;
+                       ieee80211_process_measurement_req(sdata, mgmt, len);
+                       break;
+               }
+               break;
+       default:
+               return RX_CONTINUE;
+       }
+
+       rx->sta->rx_packets++;
+       dev_kfree_skb(rx->skb);
+       return RX_QUEUED;
+}
+
+static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_MONITOR;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-       if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-            sdata->vif.type == IEEE80211_IF_TYPE_IBSS ||
-            sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) &&
-           !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
-               ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status);
-       else
+       if (ieee80211_vif_is_mesh(&sdata->vif))
+               return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
+
+       if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
+           sdata->vif.type != IEEE80211_IF_TYPE_IBSS)
                return RX_DROP_MONITOR;
 
+       if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
+               return RX_DROP_MONITOR;
+
+       ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
        return RX_QUEUED;
 }
 
@@ -1570,7 +1645,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
            !ieee80211_is_auth(hdr->frame_control))
                goto ignore;
 
-       mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr);
+       mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr);
  ignore:
        dev_kfree_skb(rx->skb);
        rx->skb = NULL;
@@ -1689,6 +1764,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
                CALL_RXH(ieee80211_rx_h_mesh_fwding);
        CALL_RXH(ieee80211_rx_h_data)
        CALL_RXH(ieee80211_rx_h_ctrl)
+       CALL_RXH(ieee80211_rx_h_action)
        CALL_RXH(ieee80211_rx_h_mgmt)
 
 #undef CALL_RXH
@@ -1743,10 +1819,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                if (!bssid)
                        return 0;
                if (ieee80211_is_beacon(hdr->frame_control)) {
-                       if (!rx->sta)
-                               rx->sta = ieee80211_ibss_add_sta(sdata->dev,
-                                               rx->skb, bssid, hdr->addr2,
-                                               BIT(rx->status->rate_idx));
                        return 1;
                }
                else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
@@ -1760,7 +1832,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!rx->sta)
-                       rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
+                       rx->sta = ieee80211_ibss_add_sta(sdata, rx->skb,
                                                bssid, hdr->addr2,
                                                BIT(rx->status->rate_idx));
                break;
@@ -2066,7 +2138,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
        /* if this mpdu is fragmented - terminate rx aggregation session */
        sc = le16_to_cpu(hdr->seq_ctrl);
        if (sc & IEEE80211_SCTL_FRAG) {
-               ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
+               ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->addr,
                        tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
                ret = 1;
                goto end_reorder;