Merge branch 'upstream-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
[powerpc.git] / drivers / net / wireless / hostap / hostap_info.c
index cf9e089..50f72d8 100644 (file)
@@ -1,5 +1,8 @@
 /* Host AP driver Info Frame processing (part of hostap.o module) */
 
+#include "hostap_wlan.h"
+#include "hostap.h"
+#include "hostap_ap.h"
 
 /* Called only as a tasklet (software IRQ) */
 static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
@@ -160,7 +163,7 @@ static void prism2_host_roaming(local_info_t *local)
 {
        struct hfa384x_join_request req;
        struct net_device *dev = local->dev;
-       struct hfa384x_scan_result *selected, *entry;
+       struct hfa384x_hostscan_result *selected, *entry;
        int i;
        unsigned long flags;
 
@@ -244,9 +247,10 @@ static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
                                    int left)
 {
        u16 *pos;
-       int new_count;
+       int new_count, i;
        unsigned long flags;
-       struct hfa384x_scan_result *results, *prev;
+       struct hfa384x_scan_result *res;
+       struct hfa384x_hostscan_result *results, *prev;
 
        if (left < 4) {
                printk(KERN_DEBUG "%s: invalid scanresult info frame "
@@ -260,11 +264,18 @@ static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
        left -= 4;
 
        new_count = left / sizeof(struct hfa384x_scan_result);
-       results = kmalloc(new_count * sizeof(struct hfa384x_scan_result),
+       results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
                          GFP_ATOMIC);
        if (results == NULL)
                return;
-       memcpy(results, pos, new_count * sizeof(struct hfa384x_scan_result));
+
+       /* Convert to hostscan result format. */
+       res = (struct hfa384x_scan_result *) pos;
+       for (i = 0; i < new_count; i++) {
+               memcpy(&results[i], &res[i],
+                      sizeof(struct hfa384x_scan_result));
+               results[i].atim = 0;
+       }
 
        spin_lock_irqsave(&local->lock, flags);
        local->last_scan_type = PRISM2_SCAN;
@@ -335,9 +346,9 @@ static void prism2_info_hostscanresults(local_info_t *local,
 
        spin_lock_irqsave(&local->lock, flags);
        local->last_scan_type = PRISM2_HOSTSCAN;
-       prev = local->last_hostscan_results;
-       local->last_hostscan_results = results;
-       local->last_hostscan_results_count = new_count;
+       prev = local->last_scan_results;
+       local->last_scan_results = results;
+       local->last_scan_results_count = new_count;
        spin_unlock_irqrestore(&local->lock, flags);
        kfree(prev);
 
@@ -445,6 +456,19 @@ static void handle_info_queue_scanresults(local_info_t *local)
 {
        if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
                prism2_host_roaming(local);
+
+       if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
+           memcmp(local->preferred_ap, "\x00\x00\x00\x00\x00\x00",
+                  ETH_ALEN) != 0) {
+               /*
+                * Firmware seems to be getting into odd state in host_roaming
+                * mode 2 when hostscan is used without join command, so try
+                * to fix this by re-joining the current AP. This does not
+                * actually trigger a new association if the current AP is
+                * still in the scan results.
+                */
+               prism2_host_roaming(local);
+       }
 }