Detected networks are kept in a hashtable. Also defined functions for manipulation with that hashtable. Signed-off-by: Jiri Benc Signed-off-by: Jirka Bohac Index: netdev/include/net/ieee80211.h =================================================================== --- netdev.orig/include/net/ieee80211.h 2005-09-17 15:13:47.000000000 +0200 +++ netdev/include/net/ieee80211.h 2005-09-17 15:22:17.000000000 +0200 @@ -682,7 +682,14 @@ enum ieee80211_queue_state { /* ieee80211_network.flags */ #define NETWORK_EMPTY_ESSID (1<<0) +/* Used as index into ieee80211_device.networks array */ +typedef u8 wnetidx_t; +#define WNETIDX_MAX ((wnetidx_t)~0) + struct ieee80211_network { + /* hash table internal data */ + wnetidx_t list_start, next, prev, older, newer; + /* These entries are used to identify a unique network */ u8 bssid[IEEE80211_ALEN]; u8 channel; @@ -707,7 +714,6 @@ struct ieee80211_network { size_t wpa_ie_len; u8 rsn_ie[MAX_WPA_IE_LEN]; size_t rsn_ie_len; - struct list_head list; }; enum ieee80211_state { @@ -753,12 +759,10 @@ struct ieee80211_device { struct net_device_stats stats; struct ieee80211_stats ieee_stats; - /* Probe / Beacon management */ - struct list_head network_free_list; - struct list_head network_list; + /* Networks */ struct ieee80211_network *networks; - int scans; - int scan_age; + spinlock_t networks_lock; + wnetidx_t net_free_start, net_oldest; int iw_mode; /* operating mode (IW_MODE_*) */ struct iw_spy_data spy_data; /* iwspy support */ @@ -1021,14 +1025,18 @@ extern int ieee80211_wx_get_encode(struc struct iw_request_info *info, union iwreq_data *wrqu, char *key); -extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) -{ - ieee->scans++; -} - -extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) -{ - return ieee->scans; -} +/* ieee80211_scan.c */ +extern void ieee80211_network_update(struct ieee80211_device *ieee, + const struct ieee80211_network *n); +extern const struct ieee80211_network *ieee80211_network_find( + struct ieee80211_device *ieee, u8 *bssid); +extern void ieee80211_network_delete(struct ieee80211_device *ieee, + u8 *bssid); +extern void ieee80211_networks_flush(struct ieee80211_device *ieee); +extern int ieee80211_networks_foreach(struct ieee80211_device *ieee, + int (*callback)(struct ieee80211_network *, + struct ieee80211_device *, + void *), + void *priv); #endif /* IEEE80211_H */ Index: netdev/net/ieee80211/Makefile =================================================================== --- netdev.orig/net/ieee80211/Makefile 2005-09-17 14:52:53.000000000 +0200 +++ netdev/net/ieee80211/Makefile 2005-09-17 15:20:53.000000000 +0200 @@ -8,5 +8,6 @@ ieee80211-objs := \ ieee80211_proto.o \ ieee80211_tx.o \ ieee80211_rx.o \ + ieee80211_scan.o \ ieee80211_wx.o Index: netdev/net/ieee80211/ieee80211_scan.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ netdev/net/ieee80211/ieee80211_scan.c 2005-09-17 15:20:53.000000000 +0200 @@ -0,0 +1,247 @@ +/* + * Scanning and network list. + * + * Copyright (c) 2005 Andrea Merello + * Copyright (c) 2005 Jiri Benc and Jirka Bohac + * + * Sponsored by SUSE. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See README and COPYING for + * more details. + */ +#include +#include + +/* Found networks are kept in a hash table. + * struct ieee80211_network has the following members: + * list_start -- index of the first element of the list of networks + * with hash equal to the given index + * next -- index of the next network with the same hash; also used + * to keep track of empty entries + * prev -- index of the previous network with the same hash + * older -- index of the network that was updated right before the current one + * newer -- index of the network that was updated right after the current one + */ + +static inline wnetidx_t compute_hash(const u8 *bssid) +{ + return bssid[IEEE80211_ALEN - 1]; +} + +/* Allocate the table and initialize into an empty state. */ +int ieee80211_networks_init(struct ieee80211_device *ieee) +{ + spin_lock_init(&ieee->networks_lock); + ieee->networks = kmalloc(sizeof(*ieee->networks) * WNETIDX_MAX, + GFP_KERNEL); + if (!ieee->networks) + return -ENOMEM; + + ieee80211_networks_flush(ieee); + return 0; +} + +/* Clean up. */ +void ieee80211_networks_free(struct ieee80211_device *ieee) +{ + kfree(ieee->networks); + ieee->networks = NULL; +} + +/* Reinitialize to an empty state. */ +void ieee80211_networks_flush(struct ieee80211_device *ieee) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&ieee->networks_lock, flags); + ieee->net_free_start = 0; + ieee->net_oldest = WNETIDX_MAX; + for (i = 0; i < WNETIDX_MAX; i++) { + ieee->networks[i].list_start = WNETIDX_MAX; + ieee->networks[i].next = i + 1; + /* index of the last item is (WNETIDX_MAX - 1), so it will + * have 'next' correctly set to WNETIDX_MAX */ + } + spin_unlock_irqrestore(&ieee->networks_lock, flags); +} +EXPORT_SYMBOL(ieee80211_networks_flush); + +/* Unlinks the given entry from all the lists, adds it to the "empty" list. + * The caller must hold networks_lock. */ +static inline void __network_delete(struct ieee80211_device *ieee, wnetidx_t idx) +{ + struct ieee80211_network *n = ieee->networks + idx; + + if (n->prev != WNETIDX_MAX) + ieee->networks[n->prev].next = n->next; + else + ieee->networks[compute_hash(n->bssid)].list_start = n->next; + + if (n->next != WNETIDX_MAX) + ieee->networks[n->next].prev = n->prev; + + if (n->newer != n->older) { + ieee->networks[n->older].newer = n->newer; + ieee->networks[n->newer].older = n->older; + } else + n->newer = WNETIDX_MAX; + + if (ieee->net_oldest == idx) + ieee->net_oldest = n->newer; + + n->next = ieee->net_free_start; + ieee->net_free_start = idx; +} + +/* Adds a new network to the table. Network is not added to the + * oldest..newest list. The caller must hold networks_lock. */ +static inline wnetidx_t __network_add(struct ieee80211_device *ieee, + const u8 *bssid) +{ + struct ieee80211_network *new; + wnetidx_t i, new_idx; + + /* delete the oldest net if no more space */ + if (ieee->net_free_start == WNETIDX_MAX) + __network_delete(ieee, ieee->net_oldest); + + new_idx = ieee->net_free_start; + new = ieee->networks + new_idx; + + ieee->net_free_start = new->next; + + i = compute_hash(bssid); + new->next = ieee->networks[i].list_start; + ieee->networks[i].list_start = new_idx; + new->prev = WNETIDX_MAX; + ieee->networks[new->next].prev = new_idx; + + new->older = new->newer = new_idx; + new->last_associate = 0; + + /* first network after a flush */ + if (unlikely(ieee->net_oldest == WNETIDX_MAX)) + ieee->net_oldest = new_idx; + + return new_idx; +} + +/* Find a network based on the bssid. The caller must hold networks_lock. */ +static inline wnetidx_t __network_find(struct ieee80211_device *ieee, + const u8 *bssid) +{ + wnetidx_t i; + + i = ieee->networks[compute_hash(bssid)].list_start; + while (i != WNETIDX_MAX && + memcmp(ieee->networks[i].bssid, bssid, IEEE80211_ALEN)) + i = ieee->networks[i].next; + return i; +} + +/* Finds or adds the given network in the table and copies the supplied data + * into it (except for the hash-tables's internal data). */ +void ieee80211_network_update(struct ieee80211_device *ieee, + const struct ieee80211_network *n) +{ + wnetidx_t i, bk_ls, bk_next, bk_prev; + u32 bk_last_assoc; + struct ieee80211_network *new; + unsigned long flags; + + spin_lock_irqsave(&ieee->networks_lock, flags); + i = __network_find(ieee, n->bssid); + if (unlikely(i == WNETIDX_MAX)) + i = __network_add(ieee, n->bssid); + new = ieee->networks + i; + + /* update the newer/older links of neighbouring items */ + ieee->networks[new->older].newer = new->newer; + ieee->networks[new->newer].older = new->older; + if (ieee->net_oldest == i) + ieee->net_oldest = new->newer; + + /* save hash-table's internal data before copying */ + bk_ls = new->list_start; + bk_next = new->next; + bk_prev = new->prev; + bk_last_assoc = new->last_associate; + + *new = *n; + + new->list_start = bk_ls; + new->next = bk_next; + new->prev = bk_prev; + new->last_associate = bk_last_assoc; + + /* reconnect this net in the oldest..newest list */ + new->newer = ieee->net_oldest; + new->older = ieee->networks[ieee->net_oldest].older; + ieee->networks[new->newer].older = i; + ieee->networks[new->older].newer = i; + + spin_unlock_irqrestore(&ieee->networks_lock, flags); +} +EXPORT_SYMBOL(ieee80211_network_update); + + +/* Returns the network with the given bssid or NULL if it does not exist. */ +const struct ieee80211_network *ieee80211_network_find( + struct ieee80211_device *ieee, u8 *bssid) +{ + wnetidx_t i; + unsigned long flags; + + spin_lock_irqsave(&ieee->networks_lock, flags); + i = __network_find(ieee, bssid); + spin_unlock_irqrestore(&ieee->networks_lock, flags); + return i == WNETIDX_MAX ? NULL : ieee->networks + i; +} +EXPORT_SYMBOL(ieee80211_network_find); + + +/* Frees network with the given bssid. */ +void ieee80211_network_delete(struct ieee80211_device *ieee, u8 *bssid) +{ + wnetidx_t i; + unsigned long flags; + + spin_lock_irqsave(&ieee->networks_lock, flags); + i = __network_find(ieee, bssid); + if (i != WNETIDX_MAX) + __network_delete(ieee, i); + spin_unlock_irqrestore(&ieee->networks_lock, flags); +} +EXPORT_SYMBOL(ieee80211_network_delete); + + +/* Calls given callback on each network. Networks are passed from the newest + * to the oldest one. The callback is called in atomic context. It can + * return nonzero value to stop walking through networks. Return value is + * the one returned by the last callback call. */ +int ieee80211_networks_foreach(struct ieee80211_device *ieee, + int (*callback)(struct ieee80211_network *, + struct ieee80211_device *, + void *), + void *priv) +{ + wnetidx_t i; + int res = 0; + unsigned long flags; + + spin_lock_irqsave(&ieee->networks_lock, flags); + i = ieee->net_oldest; + if (i == WNETIDX_MAX) + goto exit; + do { + i = ieee->networks[i].older; + res = callback(ieee->networks + i, ieee, priv); + } while (!res && i != ieee->net_oldest); +exit: + spin_unlock_irqrestore(&ieee->networks_lock, flags); + return res; +} +EXPORT_SYMBOL(ieee80211_networks_foreach); Index: netdev/net/ieee80211/ieee80211_module.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_module.c 2005-09-17 15:09:39.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_module.c 2005-09-17 15:20:53.000000000 +0200 @@ -80,25 +80,6 @@ static inline int ieee80211_networks_all return 0; } -static inline void ieee80211_networks_free(struct ieee80211_device *ieee) -{ - if (!ieee->networks) - return; - kfree(ieee->networks); - ieee->networks = NULL; -} - -static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) -{ - int i; - - INIT_LIST_HEAD(&ieee->network_free_list); - INIT_LIST_HEAD(&ieee->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) - list_add_tail(&ieee->networks[i].list, - &ieee->network_free_list); -} - struct ieee80211_device *alloc_ieee80211(int sizeof_priv) { struct ieee80211_device *ieee; @@ -125,7 +106,7 @@ struct ieee80211_device *alloc_ieee80211 IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err); goto failed; } - ieee80211_networks_initialize(ieee); + ieee80211_networks_init(ieee); /* Set default config values */ ieee->config = @@ -137,7 +118,6 @@ struct ieee80211_device *alloc_ieee80211 /* Default fragmentation threshold is maximum payload size */ ieee->fts = DEFAULT_FTS; ieee->seq_number = 0; - ieee->scan_age = DEFAULT_MAX_SCAN_AGE; ieee->open_wep = 1; /* Default to enabling full open WEP with host based encrypt/decrypt */ Index: netdev/net/ieee80211/ieee80211_layer.h =================================================================== --- netdev.orig/net/ieee80211/ieee80211_layer.h 2005-09-17 15:09:39.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_layer.h 2005-09-17 15:20:53.000000000 +0200 @@ -16,4 +16,8 @@ /* ieee80211_tx.c */ extern void __ieee80211_tx_task(unsigned long data); +/* ieee80211_scan.c */ +extern int ieee80211_networks_init(struct ieee80211_device *ieee); +extern void ieee80211_networks_free(struct ieee80211_device *ieee); + #endif Index: netdev/net/ieee80211/ieee80211_wx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_wx.c 2005-09-17 15:20:25.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_wx.c 2005-09-17 15:20:53.000000000 +0200 @@ -36,11 +36,41 @@ #include #include +struct translate_scan { + char *start; + char *stop; + int count; +}; + +/* wrappers of WE functions that don't check for errors */ +static inline int iwe_stream_try_add_point(struct translate_scan *data, + struct iw_event *iwe, char *extra) +{ + char *new_start; + new_start = iwe_stream_add_point(data->start, data->stop, iwe, extra); + if (unlikely(new_start == data->start)) + return -E2BIG; + data->start = new_start; + return 0; +} + +static inline int iwe_stream_try_add_event(struct translate_scan *data, + struct iw_event *iwe, int len) +{ + char *new_start; + new_start = iwe_stream_add_event(data->start, data->stop, iwe, len); + if (unlikely(new_start == data->start)) + return -E2BIG; + data->start = new_start; + return 0; +} + #define MAX_CUSTOM_LEN 64 -static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, - char *start, char *stop, - struct ieee80211_network *network) +static int ieee80211_translate_scan(struct ieee80211_network *network, + struct ieee80211_device *ieee, + void *__data) { + struct translate_scan *data = __data; char custom[MAX_CUSTOM_LEN]; char *p; struct iw_event iwe; @@ -48,11 +78,23 @@ static inline char *ipw2100_translate_sc u8 max_rate, rate; char mode[4]; + if (!time_after(network->last_scanned + DEFAULT_MAX_SCAN_AGE, jiffies)) { + IEEE80211_DEBUG_SCAN( + "Not showing network '%s (" + MAC_FMT ")' due to age (%lums).\n", + escape_essid(network->ssid, + network->ssid_len), + MAC_ARG(network->bssid), + (jiffies - network->last_scanned) / (HZ / 100)); + return 1; + } + /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, network->bssid, IEEE80211_ALEN); - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); + if (iwe_stream_try_add_event(data, &iwe, IW_EV_ADDR_LEN)) + return -E2BIG; /* Remaining entries will be displayed in the order we provide them */ @@ -61,10 +103,12 @@ static inline char *ipw2100_translate_sc iwe.u.data.flags = 1; if (network->flags & NETWORK_EMPTY_ESSID) { iwe.u.data.length = sizeof(""); - start = iwe_stream_add_point(start, stop, &iwe, ""); + if (iwe_stream_try_add_point(data, &iwe, "")) + return -E2BIG; } else { iwe.u.data.length = min(network->ssid_len, (u8) 32); - start = iwe_stream_add_point(start, stop, &iwe, network->ssid); + if (iwe_stream_try_add_point(data, &iwe, network->ssid)) + return -E2BIG; } /* Add the protocol name */ @@ -77,7 +121,8 @@ static inline char *ipw2100_translate_sc if (network->modulations & IEEE80211_G_MANDATORY_MODULATIONS) strcat(mode, "g"); snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", mode); - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); + if (iwe_stream_try_add_event(data, &iwe, IW_EV_CHAR_LEN)) + return -E2BIG; /* Add mode */ iwe.cmd = SIOCGIWMODE; @@ -87,7 +132,8 @@ static inline char *ipw2100_translate_sc else iwe.u.mode = IW_MODE_ADHOC; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); + if (iwe_stream_try_add_event(data, &iwe, IW_EV_UINT_LEN)) + return -E2BIG; } /* Add frequency/channel */ @@ -97,7 +143,8 @@ static inline char *ipw2100_translate_sc iwe.u.freq.m = network->channel; iwe.u.freq.e = 0; iwe.u.freq.i = 0; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); + if (iwe_stream_try_add_event(data, &iwe, IW_EV_FREQ_LEN)) + return -E2BIG; /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; @@ -106,7 +153,8 @@ static inline char *ipw2100_translate_sc else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - start = iwe_stream_add_point(start, stop, &iwe, network->ssid); + if (iwe_stream_try_add_point(data, &iwe, network->ssid)) + return -E2BIG; /* Add basic and extended rates */ max_rate = 0; @@ -125,12 +173,14 @@ static inline char *ipw2100_translate_sc iwe.cmd = SIOCGIWRATE; iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; iwe.u.bitrate.value = max_rate * 500000; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN); + if (iwe_stream_try_add_event(data, &iwe, IW_EV_PARAM_LEN)) + return -E2BIG; iwe.cmd = IWEVCUSTOM; iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point(start, stop, &iwe, custom); + if (iwe_stream_try_add_point(data, &iwe, custom)) + return -E2BIG; /* Add quality statistics */ iwe.cmd = IWEVQUAL; @@ -145,14 +195,16 @@ static inline char *ipw2100_translate_sc iwe.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; iwe.u.qual.updated |= (~iwe.u.qual.updated >> 4) & 7; - start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); + if (iwe_stream_try_add_event(data, &iwe, IW_EV_QUAL_LEN)) + return -E2BIG; iwe.cmd = IWEVCUSTOM; p = custom; iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point(start, stop, &iwe, custom); + if (iwe_stream_try_add_point(data, &iwe, custom)) + return -E2BIG; if (ieee->wpa_enabled && network->wpa_ie_len) { char buf[MAX_WPA_IE_LEN * 2 + 30]; @@ -166,7 +218,8 @@ static inline char *ipw2100_translate_sc memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = strlen(buf); - start = iwe_stream_add_point(start, stop, &iwe, buf); + if (iwe_stream_try_add_point(data, &iwe, buf)) + return -E2BIG; } if (ieee->wpa_enabled && network->rsn_ie_len) { @@ -181,7 +234,8 @@ static inline char *ipw2100_translate_sc memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = strlen(buf); - start = iwe_stream_add_point(start, stop, &iwe, buf); + if (iwe_stream_try_add_point(data, &iwe, buf)) + return -E2BIG; } /* Add EXTRA: Age to display seconds since last beacon/probe response @@ -193,50 +247,35 @@ static inline char *ipw2100_translate_sc (jiffies - network->last_scanned) / (HZ / 100)); iwe.u.data.length = p - custom; if (iwe.u.data.length) - start = iwe_stream_add_point(start, stop, &iwe, custom); + if (iwe_stream_try_add_point(data, &iwe, custom)) + return -E2BIG; - return start; + data->count++; + return 0; } int ieee80211_wx_get_scan(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct ieee80211_network *network; - unsigned long flags; - - char *ev = extra; - char *stop = ev + IW_SCAN_MAX_DATA; - int i = 0; + int res; + struct translate_scan data = { + .start = extra, + .stop = extra + wrqu->data.length, + .count = 0 + }; IEEE80211_DEBUG_WX("Getting scan\n"); - spin_lock_irqsave(&ieee->lock, flags); + res = ieee80211_networks_foreach(ieee, ieee80211_translate_scan, &data); + if (res > 0) res = 0; - list_for_each_entry(network, &ieee->network_list, list) { - i++; - if (ieee->scan_age == 0 || - time_after(network->last_scanned + ieee->scan_age, jiffies)) - ev = ipw2100_translate_scan(ieee, ev, stop, network); - else - IEEE80211_DEBUG_SCAN("Not showing network '%s (" - MAC_FMT ")' due to age (%lums).\n", - escape_essid(network->ssid, - network->ssid_len), - MAC_ARG(network->bssid), - (jiffies - - network->last_scanned) / (HZ / - 100)); - } - - spin_unlock_irqrestore(&ieee->lock, flags); - - wrqu->data.length = ev - extra; + wrqu->data.length = data.start - extra; wrqu->data.flags = 0; - IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); + IEEE80211_DEBUG_WX("exit: %d networks returned.\n", data.count); - return 0; + return res; } int ieee80211_wx_set_encode(struct ieee80211_device *ieee, Index: netdev/net/ieee80211/ieee80211_rx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_rx.c 2005-09-17 15:18:57.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_rx.c 2005-09-17 15:21:31.000000000 +0200 @@ -951,45 +951,6 @@ static inline int ieee80211_network_init return 0; } -static inline int is_same_network(struct ieee80211_network *src, - struct ieee80211_network *dst) -{ - /* A network is only a duplicate if the channel, BSSID, and ESSID - * all match. We treat all with the same BSSID and channel - * as one network */ - return ((src->ssid_len == dst->ssid_len) && - (src->channel == dst->channel) && - !memcmp(src->bssid, dst->bssid, IEEE80211_ALEN) && - !memcmp(src->ssid, dst->ssid, src->ssid_len)); -} - -static inline void update_network(struct ieee80211_network *dst, - struct ieee80211_network *src) -{ - dst->signal = src->signal; - dst->noise = src->noise; - dst->capability = src->capability; - dst->modulations = src->modulations; - dst->rates = src->rates; - dst->rates_ex = src->rates_ex; - - dst->flags = src->flags; - dst->time_stamp[0] = src->time_stamp[0]; - dst->time_stamp[1] = src->time_stamp[1]; - - dst->beacon_interval = src->beacon_interval; - dst->listen_interval = src->listen_interval; - dst->atim_window = src->atim_window; - - memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); - dst->wpa_ie_len = src->wpa_ie_len; - memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); - dst->rsn_ie_len = src->rsn_ie_len; - - dst->last_scanned = jiffies; - /* dst->last_associate is not overwritten */ -} - static inline void ieee80211_process_probe_response(struct ieee80211_device *ieee, struct ieee80211_probe_response *beacon, @@ -997,12 +958,9 @@ static inline void ieee80211_process_pro struct ieee80211_rx_info *info) { struct ieee80211_network network; - struct ieee80211_network *target; - struct ieee80211_network *oldest = NULL; #ifdef CONFIG_IEEE80211_DEBUG struct ieee80211_info_element *info_element = beacon->info_element; #endif - unsigned long flags; IEEE80211_DEBUG_SCAN("'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", @@ -1039,73 +997,8 @@ static inline void ieee80211_process_pro return; } - /* The network parsed correctly -- so now we scan our known networks - * to see if we can find it in our list. - * - * NOTE: This search is definitely not optimized. Once its doing - * the "right thing" we'll optimize it for efficiency if - * necessary */ - - /* Search for this entry in the list and update it if it is - * already there. */ - - spin_lock_irqsave(&ieee->lock, flags); - - list_for_each_entry(target, &ieee->network_list, list) { - if (is_same_network(target, &network)) - break; - - if ((oldest == NULL) || - (target->last_scanned < oldest->last_scanned)) - oldest = target; - } - - /* If we didn't find a match, then get a new network slot to initialize - * with this beacon's information */ - if (&target->list == &ieee->network_list) { - if (list_empty(&ieee->network_free_list)) { - /* If there are no more slots, expire the oldest */ - list_del(&oldest->list); - target = oldest; - IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " - "network list.\n", - escape_essid(target->ssid, - target->ssid_len), - MAC_ARG(target->bssid)); - } else { - /* Otherwise just pull from the free list */ - target = list_entry(ieee->network_free_list.next, - struct ieee80211_network, list); - list_del(ieee->network_free_list.next); - } - -#ifdef CONFIG_IEEE80211_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", - escape_essid(network.ssid, - network.ssid_len), - MAC_ARG(network.bssid), - WLAN_FC_GET_STYPE(le16_to_cpu - (beacon->header. - frame_ctl)) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); -#endif - memcpy(target, &network, sizeof(*target)); - list_add_tail(&target->list, &ieee->network_list); - } else { - IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", - escape_essid(target->ssid, - target->ssid_len), - MAC_ARG(target->bssid), - WLAN_FC_GET_STYPE(le16_to_cpu - (beacon->header. - frame_ctl)) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); - update_network(target, &network); - } - - spin_unlock_irqrestore(&ieee->lock, flags); + /* The network parsed correctly. */ + ieee80211_network_update(ieee, &network); } static int ieee80211_rx_mgmt(struct ieee80211_device *ieee,