[PATCH] cfq-iosched: fix crash in do_div()
[safe/jmp/linux-2.6] / net / ieee80211 / ieee80211_rx.c
index 6c070bc..604b7b0 100644 (file)
@@ -369,8 +369,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 
        /* Put this code here so that we avoid duplicating it in all
         * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
 #ifdef IW_WIRELESS_SPY         /* defined in iw_handler.h */
-#ifdef CONFIG_NET_RADIO
        /* If spy monitoring on */
        if (ieee->spy_data.spy_number > 0) {
                struct iw_quality wstats;
@@ -397,8 +397,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                /* Update spy records */
                wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
        }
-#endif                         /* CONFIG_NET_RADIO */
 #endif                         /* IW_WIRELESS_SPY */
+#endif                         /* CONFIG_WIRELESS_EXT */
 
 #ifdef NOT_YET
        hostap_update_rx_stats(local->ap, hdr, rx_stats);
@@ -574,7 +574,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        /* skb: hdr + (possibly fragmented) plaintext payload */
        // PR: FIXME: hostap has additional conditions in the "if" below:
        // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
-       if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
+       if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
                int flen;
                struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
                IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
@@ -780,6 +780,80 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        return 0;
 }
 
+/* Filter out unrelated packets, call ieee80211_rx[_mgt] */
+int ieee80211_rx_any(struct ieee80211_device *ieee,
+                    struct sk_buff *skb, struct ieee80211_rx_stats *stats)
+{
+       struct ieee80211_hdr_4addr *hdr;
+       int is_packet_for_us;
+       u16 fc;
+
+       if (ieee->iw_mode == IW_MODE_MONITOR)
+               return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL;
+
+       hdr = (struct ieee80211_hdr_4addr *)skb->data;
+       fc = le16_to_cpu(hdr->frame_ctl);
+
+       if ((fc & IEEE80211_FCTL_VERS) != 0)
+               return -EINVAL;
+               
+       switch (fc & IEEE80211_FCTL_FTYPE) {
+       case IEEE80211_FTYPE_MGMT:
+               ieee80211_rx_mgt(ieee, hdr, stats);
+               return 0;
+       case IEEE80211_FTYPE_DATA:
+               break;
+       case IEEE80211_FTYPE_CTL:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       is_packet_for_us = 0;
+       switch (ieee->iw_mode) {
+       case IW_MODE_ADHOC:
+               /* our BSS and not from/to DS */
+               if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0)
+               if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
+                       /* promisc: get all */
+                       if (ieee->dev->flags & IFF_PROMISC)
+                               is_packet_for_us = 1;
+                       /* to us */
+                       else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+                               is_packet_for_us = 1;
+                       /* mcast */
+                       else if (is_multicast_ether_addr(hdr->addr1))
+                               is_packet_for_us = 1;
+               }
+               break;
+       case IW_MODE_INFRA:
+               /* our BSS (== from our AP) and from DS */
+               if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0)
+               if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
+                       /* promisc: get all */
+                       if (ieee->dev->flags & IFF_PROMISC)
+                               is_packet_for_us = 1;
+                       /* to us */
+                       else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+                               is_packet_for_us = 1;
+                       /* mcast */
+                       else if (is_multicast_ether_addr(hdr->addr1)) {
+                               /* not our own packet bcasted from AP */
+                               if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN))
+                                       is_packet_for_us = 1;
+                       }
+               }
+               break;
+       default:
+               /* ? */
+               break;
+       }
+
+       if (is_packet_for_us)
+               return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL);
+       return 0;
+}
+
 #define MGMT_FRAME_FIXED_PART_LENGTH           0x24
 
 static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
@@ -1345,7 +1419,19 @@ static void update_network(struct ieee80211_network *dst,
        ieee80211_network_reset(dst);
        dst->ibss_dfs = src->ibss_dfs;
 
-       memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
+       /* We only update the statistics if they were created by receiving
+        * the network information on the actual channel the network is on.
+        * 
+        * This keeps beacons received on neighbor channels from bringing
+        * down the signal level of an AP. */
+       if (dst->channel == src->stats.received_channel)
+               memcpy(&dst->stats, &src->stats,
+                      sizeof(struct ieee80211_rx_stats));
+       else
+               IEEE80211_DEBUG_SCAN("Network " MAC_FMT " info received "
+                       "off channel (%d vs. %d)\n", MAC_ARG(src->bssid),
+                       dst->channel, src->stats.received_channel);
+
        dst->capability = src->capability;
        memcpy(dst->rates, src->rates, src->rates_len);
        dst->rates_len = src->rates_len;
@@ -1394,7 +1480,7 @@ static void update_network(struct ieee80211_network *dst,
        /* dst->last_associate is not overwritten */
 }
 
-static inline int is_beacon(int fc)
+static inline int is_beacon(__le16 fc)
 {
        return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
 }
@@ -1443,9 +1529,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                                     escape_essid(info_element->data,
                                                  info_element->len),
                                     MAC_ARG(beacon->header.addr3),
-                                    is_beacon(le16_to_cpu
-                                              (beacon->header.
-                                               frame_ctl)) ?
+                                    is_beacon(beacon->header.frame_ctl) ?
                                     "BEACON" : "PROBE RESPONSE");
                return;
        }
@@ -1496,9 +1580,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                                     escape_essid(network.ssid,
                                                  network.ssid_len),
                                     MAC_ARG(network.bssid),
-                                    is_beacon(le16_to_cpu
-                                              (beacon->header.
-                                               frame_ctl)) ?
+                                    is_beacon(beacon->header.frame_ctl) ?
                                     "BEACON" : "PROBE RESPONSE");
 #endif
                memcpy(target, &network, sizeof(*target));
@@ -1509,9 +1591,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                                     escape_essid(target->ssid,
                                                  target->ssid_len),
                                     MAC_ARG(target->bssid),
-                                    is_beacon(le16_to_cpu
-                                              (beacon->header.
-                                               frame_ctl)) ?
+                                    is_beacon(beacon->header.frame_ctl) ?
                                     "BEACON" : "PROBE RESPONSE");
                update_network(target, &network);
                network.ibss_dfs = NULL;
@@ -1519,12 +1599,12 @@ static void ieee80211_process_probe_response(struct ieee80211_device
 
        spin_unlock_irqrestore(&ieee->lock, flags);
 
-       if (is_beacon(le16_to_cpu(beacon->header.frame_ctl))) {
+       if (is_beacon(beacon->header.frame_ctl)) {
                if (ieee->handle_beacon != NULL)
-                       ieee->handle_beacon(dev, beacon, &network);
+                       ieee->handle_beacon(dev, beacon, target);
        } else {
                if (ieee->handle_probe_response != NULL)
-                       ieee->handle_probe_response(dev, beacon, &network);
+                       ieee->handle_probe_response(dev, beacon, target);
        }
 }
 
@@ -1607,6 +1687,30 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                                            header, stats);
                break;
 
+       case IEEE80211_STYPE_REASSOC_REQ:
+               IEEE80211_DEBUG_MGMT("received reassoc (%d)\n",
+                                    WLAN_FC_GET_STYPE(le16_to_cpu
+                                                      (header->frame_ctl)));
+
+               IEEE80211_WARNING("%s: IEEE80211_REASSOC_REQ received\n",
+                                 ieee->dev->name);
+               if (ieee->handle_reassoc_request != NULL)
+                       ieee->handle_reassoc_request(ieee->dev,
+                                                   (struct ieee80211_reassoc_request *)
+                                                    header);
+               break;
+
+       case IEEE80211_STYPE_ASSOC_REQ:
+               IEEE80211_DEBUG_MGMT("received assoc (%d)\n",
+                                    WLAN_FC_GET_STYPE(le16_to_cpu
+                                                      (header->frame_ctl)));
+
+               IEEE80211_WARNING("%s: IEEE80211_ASSOC_REQ received\n",
+                                 ieee->dev->name);
+               if (ieee->handle_assoc_request != NULL)
+                       ieee->handle_assoc_request(ieee->dev);
+               break;
+
        case IEEE80211_STYPE_DEAUTH:
                IEEE80211_DEBUG_MGMT("DEAUTH\n");
                if (ieee->handle_deauth != NULL)