From ff1d2767d5a43c85f944e86a45284b721f66196c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 12 May 2005 22:54:16 -0400 Subject: Add HostAP wireless driver. Includes minor cleanups from Adrian Bunk . --- drivers/net/wireless/hostap/hostap_info.c | 478 ++++++++++++++++++++++++++++++ 1 file changed, 478 insertions(+) create mode 100644 drivers/net/wireless/hostap/hostap_info.c (limited to 'drivers/net/wireless/hostap/hostap_info.c') diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c new file mode 100644 index 000000000000..cf9e0898b57f --- /dev/null +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -0,0 +1,478 @@ +/* Host AP driver Info Frame processing (part of hostap.o module) */ + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf, + int left) +{ + struct hfa384x_comm_tallies *tallies; + + if (left < sizeof(struct hfa384x_comm_tallies)) { + printk(KERN_DEBUG "%s: too short (len=%d) commtallies " + "info frame\n", local->dev->name, left); + return; + } + + tallies = (struct hfa384x_comm_tallies *) buf; +#define ADD_COMM_TALLIES(name) \ +local->comm_tallies.name += le16_to_cpu(tallies->name) + ADD_COMM_TALLIES(tx_unicast_frames); + ADD_COMM_TALLIES(tx_multicast_frames); + ADD_COMM_TALLIES(tx_fragments); + ADD_COMM_TALLIES(tx_unicast_octets); + ADD_COMM_TALLIES(tx_multicast_octets); + ADD_COMM_TALLIES(tx_deferred_transmissions); + ADD_COMM_TALLIES(tx_single_retry_frames); + ADD_COMM_TALLIES(tx_multiple_retry_frames); + ADD_COMM_TALLIES(tx_retry_limit_exceeded); + ADD_COMM_TALLIES(tx_discards); + ADD_COMM_TALLIES(rx_unicast_frames); + ADD_COMM_TALLIES(rx_multicast_frames); + ADD_COMM_TALLIES(rx_fragments); + ADD_COMM_TALLIES(rx_unicast_octets); + ADD_COMM_TALLIES(rx_multicast_octets); + ADD_COMM_TALLIES(rx_fcs_errors); + ADD_COMM_TALLIES(rx_discards_no_buffer); + ADD_COMM_TALLIES(tx_discards_wrong_sa); + ADD_COMM_TALLIES(rx_discards_wep_undecryptable); + ADD_COMM_TALLIES(rx_message_in_msg_fragments); + ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); +#undef ADD_COMM_TALLIES +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf, + int left) +{ + struct hfa384x_comm_tallies32 *tallies; + + if (left < sizeof(struct hfa384x_comm_tallies32)) { + printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 " + "info frame\n", local->dev->name, left); + return; + } + + tallies = (struct hfa384x_comm_tallies32 *) buf; +#define ADD_COMM_TALLIES(name) \ +local->comm_tallies.name += le32_to_cpu(tallies->name) + ADD_COMM_TALLIES(tx_unicast_frames); + ADD_COMM_TALLIES(tx_multicast_frames); + ADD_COMM_TALLIES(tx_fragments); + ADD_COMM_TALLIES(tx_unicast_octets); + ADD_COMM_TALLIES(tx_multicast_octets); + ADD_COMM_TALLIES(tx_deferred_transmissions); + ADD_COMM_TALLIES(tx_single_retry_frames); + ADD_COMM_TALLIES(tx_multiple_retry_frames); + ADD_COMM_TALLIES(tx_retry_limit_exceeded); + ADD_COMM_TALLIES(tx_discards); + ADD_COMM_TALLIES(rx_unicast_frames); + ADD_COMM_TALLIES(rx_multicast_frames); + ADD_COMM_TALLIES(rx_fragments); + ADD_COMM_TALLIES(rx_unicast_octets); + ADD_COMM_TALLIES(rx_multicast_octets); + ADD_COMM_TALLIES(rx_fcs_errors); + ADD_COMM_TALLIES(rx_discards_no_buffer); + ADD_COMM_TALLIES(tx_discards_wrong_sa); + ADD_COMM_TALLIES(rx_discards_wep_undecryptable); + ADD_COMM_TALLIES(rx_message_in_msg_fragments); + ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments); +#undef ADD_COMM_TALLIES +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_commtallies(local_info_t *local, unsigned char *buf, + int left) +{ + if (local->tallies32) + prism2_info_commtallies32(local, buf, left); + else + prism2_info_commtallies16(local, buf, left); +} + + +#ifndef PRISM2_NO_STATION_MODES +#ifndef PRISM2_NO_DEBUG +static const char* hfa384x_linkstatus_str(u16 linkstatus) +{ + switch (linkstatus) { + case HFA384X_LINKSTATUS_CONNECTED: + return "Connected"; + case HFA384X_LINKSTATUS_DISCONNECTED: + return "Disconnected"; + case HFA384X_LINKSTATUS_AP_CHANGE: + return "Access point change"; + case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE: + return "Access point out of range"; + case HFA384X_LINKSTATUS_AP_IN_RANGE: + return "Access point in range"; + case HFA384X_LINKSTATUS_ASSOC_FAILED: + return "Association failed"; + default: + return "Unknown"; + } +} +#endif /* PRISM2_NO_DEBUG */ + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf, + int left) +{ + u16 val; + int non_sta_mode; + + /* Alloc new JoinRequests to occur since LinkStatus for the previous + * has been received */ + local->last_join_time = 0; + + if (left != 2) { + printk(KERN_DEBUG "%s: invalid linkstatus info frame " + "length %d\n", local->dev->name, left); + return; + } + + non_sta_mode = local->iw_mode == IW_MODE_MASTER || + local->iw_mode == IW_MODE_REPEAT || + local->iw_mode == IW_MODE_MONITOR; + + val = buf[0] | (buf[1] << 8); + if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) { + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n", + local->dev->name, val, hfa384x_linkstatus_str(val)); + } + + if (non_sta_mode) { + netif_carrier_on(local->dev); + netif_carrier_on(local->ddev); + return; + } + + /* Get current BSSID later in scheduled task */ + set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info); + local->prev_link_status = val; + schedule_work(&local->info_queue); +} + + +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; + int i; + unsigned long flags; + + if (local->last_join_time && + time_before(jiffies, local->last_join_time + 10 * HZ)) { + PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been " + "completed - waiting for it before issuing new one\n", + dev->name); + return; + } + + /* ScanResults are sorted: first ESS results in decreasing signal + * quality then IBSS results in similar order. + * Trivial roaming policy: just select the first entry. + * This could probably be improved by adding hysteresis to limit + * number of handoffs, etc. + * + * Could do periodic RID_SCANREQUEST or Inquire F101 to get new + * ScanResults */ + spin_lock_irqsave(&local->lock, flags); + if (local->last_scan_results == NULL || + local->last_scan_results_count == 0) { + spin_unlock_irqrestore(&local->lock, flags); + PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n", + dev->name); + return; + } + + selected = &local->last_scan_results[0]; + + if (local->preferred_ap[0] || local->preferred_ap[1] || + local->preferred_ap[2] || local->preferred_ap[3] || + local->preferred_ap[4] || local->preferred_ap[5]) { + /* Try to find preferred AP */ + PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n", + dev->name, MAC2STR(local->preferred_ap)); + for (i = 0; i < local->last_scan_results_count; i++) { + entry = &local->last_scan_results[i]; + if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) + { + PDEBUG(DEBUG_EXTRA, "%s: using preferred AP " + "selection\n", dev->name); + selected = entry; + break; + } + } + } + + memcpy(req.bssid, selected->bssid, 6); + req.channel = selected->chid; + spin_unlock_irqrestore(&local->lock, flags); + + PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n", + dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel)); + if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, + sizeof(req))) { + printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); + } + local->last_join_time = jiffies; +} + + +static void hostap_report_scan_complete(local_info_t *local) +{ + union iwreq_data wrqu; + + /* Inform user space about new scan results (just empty event, + * SIOCGIWSCAN can be used to fetch data */ + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL); + + /* Allow SIOCGIWSCAN handling to occur since we have received + * scanning result */ + local->scan_timestamp = 0; +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, + int left) +{ + u16 *pos; + int new_count; + unsigned long flags; + struct hfa384x_scan_result *results, *prev; + + if (left < 4) { + printk(KERN_DEBUG "%s: invalid scanresult info frame " + "length %d\n", local->dev->name, left); + return; + } + + pos = (u16 *) buf; + pos++; + pos++; + left -= 4; + + new_count = left / sizeof(struct hfa384x_scan_result); + results = kmalloc(new_count * sizeof(struct hfa384x_scan_result), + GFP_ATOMIC); + if (results == NULL) + return; + memcpy(results, pos, new_count * sizeof(struct hfa384x_scan_result)); + + spin_lock_irqsave(&local->lock, flags); + local->last_scan_type = PRISM2_SCAN; + 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); + + hostap_report_scan_complete(local); + + /* Perform rest of ScanResults handling later in scheduled task */ + set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info); + schedule_work(&local->info_queue); +} + + +/* Called only as a tasklet (software IRQ) */ +static void prism2_info_hostscanresults(local_info_t *local, + unsigned char *buf, int left) +{ + int i, result_size, copy_len, new_count; + struct hfa384x_hostscan_result *results, *prev; + unsigned long flags; + u16 *pos; + u8 *ptr; + + wake_up_interruptible(&local->hostscan_wq); + + if (left < 4) { + printk(KERN_DEBUG "%s: invalid hostscanresult info frame " + "length %d\n", local->dev->name, left); + return; + } + + pos = (u16 *) buf; + copy_len = result_size = le16_to_cpu(*pos); + if (result_size == 0) { + printk(KERN_DEBUG "%s: invalid result_size (0) in " + "hostscanresults\n", local->dev->name); + return; + } + if (copy_len > sizeof(struct hfa384x_hostscan_result)) + copy_len = sizeof(struct hfa384x_hostscan_result); + + pos++; + pos++; + left -= 4; + ptr = (u8 *) pos; + + new_count = left / result_size; + results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), + GFP_ATOMIC); + if (results == NULL) + return; + memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result)); + + for (i = 0; i < new_count; i++) { + memcpy(&results[i], ptr, copy_len); + ptr += result_size; + left -= result_size; + } + + if (left) { + printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n", + local->dev->name, left, result_size); + } + + 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; + spin_unlock_irqrestore(&local->lock, flags); + kfree(prev); + + hostap_report_scan_complete(local); +} +#endif /* PRISM2_NO_STATION_MODES */ + + +/* Called only as a tasklet (software IRQ) */ +void hostap_info_process(local_info_t *local, struct sk_buff *skb) +{ + struct hfa384x_info_frame *info; + unsigned char *buf; + int left; +#ifndef PRISM2_NO_DEBUG + int i; +#endif /* PRISM2_NO_DEBUG */ + + info = (struct hfa384x_info_frame *) skb->data; + buf = skb->data + sizeof(*info); + left = skb->len - sizeof(*info); + + switch (info->type) { + case HFA384X_INFO_COMMTALLIES: + prism2_info_commtallies(local, buf, left); + break; + +#ifndef PRISM2_NO_STATION_MODES + case HFA384X_INFO_LINKSTATUS: + prism2_info_linkstatus(local, buf, left); + break; + + case HFA384X_INFO_SCANRESULTS: + prism2_info_scanresults(local, buf, left); + break; + + case HFA384X_INFO_HOSTSCANRESULTS: + prism2_info_hostscanresults(local, buf, left); + break; +#endif /* PRISM2_NO_STATION_MODES */ + +#ifndef PRISM2_NO_DEBUG + default: + PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", + local->dev->name, info->len, info->type); + PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); + for (i = 0; i < (left < 100 ? left : 100); i++) + PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); + PDEBUG2(DEBUG_EXTRA, "\n"); + break; +#endif /* PRISM2_NO_DEBUG */ + } +} + + +#ifndef PRISM2_NO_STATION_MODES +static void handle_info_queue_linkstatus(local_info_t *local) +{ + int val = local->prev_link_status; + int connected; + union iwreq_data wrqu; + + connected = + val == HFA384X_LINKSTATUS_CONNECTED || + val == HFA384X_LINKSTATUS_AP_CHANGE || + val == HFA384X_LINKSTATUS_AP_IN_RANGE; + + if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID, + local->bssid, ETH_ALEN, 1) < 0) { + printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " + "LinkStatus event\n", local->dev->name); + } else { + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n", + local->dev->name, + MAC2STR((unsigned char *) local->bssid)); + if (local->wds_type & HOSTAP_WDS_AP_CLIENT) + hostap_add_sta(local->ap, local->bssid); + } + + /* Get BSSID if we have a valid AP address */ + if (connected) { + netif_carrier_on(local->dev); + netif_carrier_on(local->ddev); + memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN); + } else { + netif_carrier_off(local->dev); + netif_carrier_off(local->ddev); + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + } + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + + /* + * Filter out sequential disconnect events in order not to cause a + * flood of SIOCGIWAP events that have a race condition with EAPOL + * frames and can confuse wpa_supplicant about the current association + * status. + */ + if (connected || local->prev_linkstatus_connected) + wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); + local->prev_linkstatus_connected = connected; +} + + +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); +} + + +/* Called only as scheduled task after receiving info frames (used to avoid + * pending too much time in HW IRQ handler). */ +static void handle_info_queue(void *data) +{ + local_info_t *local = (local_info_t *) data; + + if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS, + &local->pending_info)) + handle_info_queue_linkstatus(local); + + if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS, + &local->pending_info)) + handle_info_queue_scanresults(local); +} +#endif /* PRISM2_NO_STATION_MODES */ + + +void hostap_info_init(local_info_t *local) +{ + skb_queue_head_init(&local->info_list); +#ifndef PRISM2_NO_STATION_MODES + INIT_WORK(&local->info_queue, handle_info_queue, local); +#endif /* PRISM2_NO_STATION_MODES */ +} + + +EXPORT_SYMBOL(hostap_info_init); +EXPORT_SYMBOL(hostap_info_process); -- cgit v1.2.3 From 2e4fd068e7e25e654a454ed4a425f239c0f6407a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 30 Jul 2005 12:50:02 -0700 Subject: [PATCH] hostap update Cleaned up scan result processing by converting struct hfa384x_scan_result into struct hfa384x_hostscan_result. This removes special cases from result processing since the results are only used in one, hostscan, format. Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_info.c | 24 ++++++---- drivers/net/wireless/hostap/hostap_ioctl.c | 77 ++++++++++++------------------ drivers/net/wireless/hostap/hostap_proc.c | 52 +++++++------------- drivers/net/wireless/hostap/hostap_wlan.h | 4 +- 4 files changed, 65 insertions(+), 92 deletions(-) (limited to 'drivers/net/wireless/hostap/hostap_info.c') diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index cf9e0898b57f..6ca94918e0f8 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -160,7 +160,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 +244,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 +261,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 +343,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); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 4c236e7903f5..97836198691a 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -663,7 +663,7 @@ static int hostap_join_ap(struct net_device *dev) struct hfa384x_join_request req; unsigned long flags; int i; - struct hfa384x_scan_result *entry; + struct hfa384x_hostscan_result *entry; iface = netdev_priv(dev); local = iface->local; @@ -1795,10 +1795,8 @@ static int prism2_ioctl_siwscan(struct net_device *dev, #ifndef PRISM2_NO_STATION_MODES static char * __prism2_translate_scan(local_info_t *local, - struct hfa384x_scan_result *scan, - struct hfa384x_hostscan_result *hscan, - int hostscan, - struct hostap_bss_info *bss, u8 *bssid, + struct hfa384x_hostscan_result *scan, + struct hostap_bss_info *bss, char *current_ev, char *end_buf) { int i, chan; @@ -1806,17 +1804,18 @@ static char * __prism2_translate_scan(local_info_t *local, char *current_val; u16 capabilities; u8 *pos; - u8 *ssid; + u8 *ssid, *bssid; size_t ssid_len; char *buf; if (bss) { ssid = bss->ssid; ssid_len = bss->ssid_len; + bssid = bss->bssid; } else { - ssid = hostscan ? hscan->ssid : scan->ssid; - ssid_len = le16_to_cpu(hostscan ? hscan->ssid_len : - scan->ssid_len); + ssid = scan->ssid; + ssid_len = le16_to_cpu(scan->ssid_len); + bssid = scan->bssid; } if (ssid_len > 32) ssid_len = 32; @@ -1850,8 +1849,7 @@ static char * __prism2_translate_scan(local_info_t *local, if (bss) { capabilities = bss->capab_info; } else { - capabilities = le16_to_cpu(hostscan ? hscan->capability : - scan->capability); + capabilities = le16_to_cpu(scan->capability); } if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { @@ -1866,8 +1864,8 @@ static char * __prism2_translate_scan(local_info_t *local, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; - if (hscan || scan) { - chan = hostscan ? hscan->chid : scan->chid; + if (scan) { + chan = scan->chid; } else if (bss) { chan = bss->chan; } else { @@ -1882,12 +1880,12 @@ static char * __prism2_translate_scan(local_info_t *local, IW_EV_FREQ_LEN); } - if (scan || hscan) { + if (scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; - if (hostscan) { - iwe.u.qual.level = le16_to_cpu(hscan->sl); - iwe.u.qual.noise = le16_to_cpu(hscan->anl); + if (local->last_scan_type == PRISM2_HOSTSCAN) { + iwe.u.qual.level = le16_to_cpu(scan->sl); + iwe.u.qual.noise = le16_to_cpu(scan->anl); } else { iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); @@ -1910,11 +1908,11 @@ static char * __prism2_translate_scan(local_info_t *local, current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); /* TODO: add SuppRates into BSS table */ - if (scan || hscan) { + if (scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWRATE; current_val = current_ev + IW_EV_LCP_LEN; - pos = hostscan ? hscan->sup_rates : scan->sup_rates; + pos = scan->sup_rates; for (i = 0; i < sizeof(scan->sup_rates); i++) { if (pos[i] == 0) break; @@ -1931,29 +1929,26 @@ static char * __prism2_translate_scan(local_info_t *local, /* TODO: add BeaconInt,resp_rate,atim into BSS table */ buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_KERNEL); - if (buf && (scan || hscan)) { + if (buf && scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - sprintf(buf, "bcn_int=%d", - le16_to_cpu(hostscan ? hscan->beacon_interval : - scan->beacon_interval)); + sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - sprintf(buf, "resp_rate=%d", le16_to_cpu(hostscan ? - hscan->rate : - scan->rate)); + sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); - if (hostscan && (capabilities & WLAN_CAPABILITY_IBSS)) { + if (local->last_scan_type == PRISM2_HOSTSCAN && + (capabilities & WLAN_CAPABILITY_IBSS)) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - sprintf(buf, "atim=%d", le16_to_cpu(hscan->atim)); + sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); @@ -1986,12 +1981,10 @@ static char * __prism2_translate_scan(local_info_t *local, static inline int prism2_translate_scan(local_info_t *local, char *buffer, int buflen) { - struct hfa384x_scan_result *scan; - struct hfa384x_hostscan_result *hscan; - int entries, entry, hostscan; + struct hfa384x_hostscan_result *scan; + int entry, hostscan; char *current_ev = buffer; char *end_buf = buffer + buflen; - u8 *bssid; struct list_head *ptr; spin_lock_bh(&local->lock); @@ -2003,14 +1996,9 @@ static inline int prism2_translate_scan(local_info_t *local, } hostscan = local->last_scan_type == PRISM2_HOSTSCAN; - entries = hostscan ? local->last_hostscan_results_count : - local->last_scan_results_count; - for (entry = 0; entry < entries; entry++) { + for (entry = 0; entry < local->last_scan_results_count; entry++) { int found = 0; scan = &local->last_scan_results[entry]; - hscan = &local->last_hostscan_results[entry]; - - bssid = hostscan ? hscan->bssid : scan->bssid; /* Report every SSID if the AP is using multiple SSIDs. If no * BSS record is found (e.g., when WPA mode is disabled), @@ -2018,18 +2006,16 @@ static inline int prism2_translate_scan(local_info_t *local, list_for_each(ptr, &local->bss_list) { struct hostap_bss_info *bss; bss = list_entry(ptr, struct hostap_bss_info, list); - if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { + if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) { bss->included = 1; current_ev = __prism2_translate_scan( - local, scan, hscan, hostscan, bss, - bssid, current_ev, end_buf); + local, scan, bss, current_ev, end_buf); found++; } } if (!found) { current_ev = __prism2_translate_scan( - local, scan, hscan, hostscan, NULL, bssid, - current_ev, end_buf); + local, scan, NULL, current_ev, end_buf); } /* Check if there is space for one more entry */ if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { @@ -2047,9 +2033,8 @@ static inline int prism2_translate_scan(local_info_t *local, bss = list_entry(ptr, struct hostap_bss_info, list); if (bss->included) continue; - current_ev = __prism2_translate_scan(local, NULL, NULL, 0, bss, - bss->bssid, current_ev, - end_buf); + current_ev = __prism2_translate_scan(local, NULL, bss, + current_ev, end_buf); /* Check if there is space for one more entry */ if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) { /* Ask user space to try again with a bigger buffer */ diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index 81b321ba189a..a0a4cbd4937a 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -302,20 +302,15 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, { char *p = page; local_info_t *local = (local_info_t *) data; - int entries, entry, i, len, total = 0, hostscan; - struct hfa384x_scan_result *scanres; - struct hfa384x_hostscan_result *hscanres; + int entry, i, len, total = 0; + struct hfa384x_hostscan_result *scanres; u8 *pos; p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " "SSID\n"); spin_lock_bh(&local->lock); - hostscan = local->last_scan_type == PRISM2_HOSTSCAN; - entries = hostscan ? local->last_hostscan_results_count : - local->last_scan_results_count; - for (entry = 0; entry < entries; entry++) { - hscanres = &local->last_hostscan_results[entry]; + for (entry = 0; entry < local->last_scan_results_count; entry++) { scanres = &local->last_scan_results[entry]; if (total + (p - page) <= off) { @@ -327,39 +322,26 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, if ((p - page) > (PAGE_SIZE - 200)) break; - if (hostscan) { - p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", - le16_to_cpu(hscanres->chid), - (s16) le16_to_cpu(hscanres->anl), - (s16) le16_to_cpu(hscanres->sl), - le16_to_cpu(hscanres->beacon_interval), - le16_to_cpu(hscanres->capability), - le16_to_cpu(hscanres->rate), - MAC2STR(hscanres->bssid), - le16_to_cpu(hscanres->atim)); - } else { - p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR - " N/A ", - le16_to_cpu(scanres->chid), - (s16) le16_to_cpu(scanres->anl), - (s16) le16_to_cpu(scanres->sl), - le16_to_cpu(scanres->beacon_interval), - le16_to_cpu(scanres->capability), - le16_to_cpu(scanres->rate), - MAC2STR(scanres->bssid)); - } - - pos = hostscan ? hscanres->sup_rates : scanres->sup_rates; - for (i = 0; i < sizeof(hscanres->sup_rates); i++) { + p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ", + le16_to_cpu(scanres->chid), + (s16) le16_to_cpu(scanres->anl), + (s16) le16_to_cpu(scanres->sl), + le16_to_cpu(scanres->beacon_interval), + le16_to_cpu(scanres->capability), + le16_to_cpu(scanres->rate), + MAC2STR(scanres->bssid), + le16_to_cpu(scanres->atim)); + + pos = scanres->sup_rates; + for (i = 0; i < sizeof(scanres->sup_rates); i++) { if (pos[i] == 0) break; p += sprintf(p, "<%02x>", pos[i]); } p += sprintf(p, " "); - pos = hostscan ? hscanres->ssid : scanres->ssid; - len = le16_to_cpu(hostscan ? hscanres->ssid_len : - scanres->ssid_len); + pos = scanres->ssid; + len = le16_to_cpu(scanres->ssid_len); if (len > 32) len = 32; for (i = 0; i < len; i++) { diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 91beee50c9c9..03de0ea80bbd 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -824,10 +824,8 @@ struct local_info { int host_roaming; unsigned long last_join_time; /* time of last JoinRequest */ - struct hfa384x_scan_result *last_scan_results; + struct hfa384x_hostscan_result *last_scan_results; int last_scan_results_count; - struct hfa384x_hostscan_result *last_hostscan_results; - int last_hostscan_results_count; enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; struct work_struct info_queue; long pending_info; /* bit field of pending info_queue items */ -- cgit v1.2.3 From 0c629a69fd8ec7b67566cfc052a9b1c4b927805a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 30 Jul 2005 12:50:03 -0700 Subject: [PATCH] hostap update 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. This makes background scans (iwlist wlan0 scan) not to break data connection when in host_roaming 2 mode, e.g., when using wpa_supplicant. Signed-off-by: Jouni Malinen Signed-off-by: Jeff Garzik --- drivers/net/wireless/hostap/hostap_info.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net/wireless/hostap/hostap_info.c') diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 6ca94918e0f8..5aa998fdf1c4 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -453,6 +453,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); + } } -- cgit v1.2.3