diff options
author | Dan Williams <dcbw@redhat.com> | 2007-05-25 16:15:56 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2007-06-11 14:28:41 -0400 |
commit | fcdb53dbc743f288bf72e485fefb3a967b733686 (patch) | |
tree | ceafcff8076af2da654214e3b72caa7b15164a28 /drivers/net/wireless/libertas/scan.c | |
parent | 90e8eafc93ed159846bb7126af8502f2a8570a11 (diff) |
[PATCH] libertas: make scan result handling more flexible
- use a linked list for scan results
- age scan results
- pass bss_descriptors around instead of indexes into the scan table
- lock access to the scan results
- stop returning EAGAIN from SIOCGIWSCAN handler
Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/scan.c')
-rw-r--r-- | drivers/net/wireless/libertas/scan.c | 1225 |
1 files changed, 552 insertions, 673 deletions
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e009f9bd0ec7..b2919a6876e6 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/if.h> | 8 | #include <linux/if.h> |
9 | #include <linux/netdevice.h> | 9 | #include <linux/netdevice.h> |
10 | #include <linux/wireless.h> | 10 | #include <linux/wireless.h> |
11 | #include <linux/etherdevice.h> | ||
11 | 12 | ||
12 | #include <net/ieee80211.h> | 13 | #include <net/ieee80211.h> |
13 | #include <net/iw_handler.h> | 14 | #include <net/iw_handler.h> |
@@ -58,12 +59,81 @@ | |||
58 | //! Scan time specified in the channel TLV for each channel for active scans | 59 | //! Scan time specified in the channel TLV for each channel for active scans |
59 | #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 | 60 | #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 |
60 | 61 | ||
61 | //! Macro to enable/disable SSID checking before storing a scan table | 62 | static inline void clear_bss_descriptor (struct bss_descriptor * bss) |
62 | #ifdef DISCARD_BAD_SSID | 63 | { |
63 | #define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid) | 64 | /* Don't blow away ->list, just BSS data */ |
64 | #else | 65 | memset(bss, 0, offsetof(struct bss_descriptor, list)); |
65 | #define CHECK_SSID_IS_VALID(x) 1 | 66 | } |
66 | #endif | 67 | |
68 | static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, | ||
69 | struct bss_descriptor * match_bss) | ||
70 | { | ||
71 | if ( !secinfo->wep_enabled | ||
72 | && !secinfo->WPAenabled | ||
73 | && !secinfo->WPA2enabled | ||
74 | && match_bss->wpa_ie[0] != WPA_IE | ||
75 | && match_bss->rsn_ie[0] != WPA2_IE | ||
76 | && !match_bss->privacy) { | ||
77 | return 1; | ||
78 | } | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo, | ||
83 | struct bss_descriptor * match_bss) | ||
84 | { | ||
85 | if ( secinfo->wep_enabled | ||
86 | && !secinfo->WPAenabled | ||
87 | && !secinfo->WPA2enabled | ||
88 | && match_bss->privacy) { | ||
89 | return 1; | ||
90 | } | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, | ||
95 | struct bss_descriptor * match_bss) | ||
96 | { | ||
97 | if ( !secinfo->wep_enabled | ||
98 | && secinfo->WPAenabled | ||
99 | && !secinfo->WPA2enabled | ||
100 | && (match_bss->wpa_ie[0] == WPA_IE) | ||
101 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
102 | && bss->privacy */ | ||
103 | ) { | ||
104 | return 1; | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, | ||
110 | struct bss_descriptor * match_bss) | ||
111 | { | ||
112 | if ( !secinfo->wep_enabled | ||
113 | && !secinfo->WPAenabled | ||
114 | && secinfo->WPA2enabled | ||
115 | && (match_bss->rsn_ie[0] == WPA2_IE) | ||
116 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
117 | && bss->privacy */ | ||
118 | ) { | ||
119 | return 1; | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, | ||
125 | struct bss_descriptor * match_bss) | ||
126 | { | ||
127 | if ( !secinfo->wep_enabled | ||
128 | && !secinfo->WPAenabled | ||
129 | && !secinfo->WPA2enabled | ||
130 | && (match_bss->wpa_ie[0] != WPA_IE) | ||
131 | && (match_bss->rsn_ie[0] != WPA2_IE) | ||
132 | && match_bss->privacy) { | ||
133 | return 1; | ||
134 | } | ||
135 | return 0; | ||
136 | } | ||
67 | 137 | ||
68 | /** | 138 | /** |
69 | * @brief Check if a scanned network compatible with the driver settings | 139 | * @brief Check if a scanned network compatible with the driver settings |
@@ -84,121 +154,63 @@ | |||
84 | * | 154 | * |
85 | * @return Index in scantable, or error code if negative | 155 | * @return Index in scantable, or error code if negative |
86 | */ | 156 | */ |
87 | static int is_network_compatible(wlan_adapter * adapter, int index, u8 mode) | 157 | static int is_network_compatible(wlan_adapter * adapter, |
158 | struct bss_descriptor * bss, u8 mode) | ||
88 | { | 159 | { |
160 | int matched = 0; | ||
161 | |||
89 | lbs_deb_enter(LBS_DEB_ASSOC); | 162 | lbs_deb_enter(LBS_DEB_ASSOC); |
90 | 163 | ||
91 | if (adapter->scantable[index].mode == mode) { | 164 | if (bss->mode != mode) |
92 | if ( !adapter->secinfo.wep_enabled | 165 | goto done; |
93 | && !adapter->secinfo.WPAenabled | ||
94 | && !adapter->secinfo.WPA2enabled | ||
95 | && adapter->scantable[index].wpa_ie[0] != WPA_IE | ||
96 | && adapter->scantable[index].rsn_ie[0] != WPA2_IE | ||
97 | && !adapter->scantable[index].privacy) { | ||
98 | /* no security */ | ||
99 | goto done; | ||
100 | } else if ( adapter->secinfo.wep_enabled | ||
101 | && !adapter->secinfo.WPAenabled | ||
102 | && !adapter->secinfo.WPA2enabled | ||
103 | && adapter->scantable[index].privacy) { | ||
104 | /* static WEP enabled */ | ||
105 | goto done; | ||
106 | } else if ( !adapter->secinfo.wep_enabled | ||
107 | && adapter->secinfo.WPAenabled | ||
108 | && !adapter->secinfo.WPA2enabled | ||
109 | && (adapter->scantable[index].wpa_ie[0] == WPA_IE) | ||
110 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
111 | && adapter->scantable[index].privacy */ | ||
112 | ) { | ||
113 | /* WPA enabled */ | ||
114 | lbs_deb_scan( | ||
115 | "is_network_compatible() WPA: index=%d wpa_ie=%#x " | ||
116 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | ||
117 | "privacy=%#x\n", index, | ||
118 | adapter->scantable[index].wpa_ie[0], | ||
119 | adapter->scantable[index].rsn_ie[0], | ||
120 | adapter->secinfo.wep_enabled ? "e" : "d", | ||
121 | adapter->secinfo.WPAenabled ? "e" : "d", | ||
122 | adapter->secinfo.WPA2enabled ? "e" : "d", | ||
123 | adapter->scantable[index].privacy); | ||
124 | goto done; | ||
125 | } else if ( !adapter->secinfo.wep_enabled | ||
126 | && !adapter->secinfo.WPAenabled | ||
127 | && adapter->secinfo.WPA2enabled | ||
128 | && (adapter->scantable[index].rsn_ie[0] == WPA2_IE) | ||
129 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
130 | && adapter->scantable[index].privacy */ | ||
131 | ) { | ||
132 | /* WPA2 enabled */ | ||
133 | lbs_deb_scan( | ||
134 | "is_network_compatible() WPA2: index=%d wpa_ie=%#x " | ||
135 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | ||
136 | "privacy=%#x\n", index, | ||
137 | adapter->scantable[index].wpa_ie[0], | ||
138 | adapter->scantable[index].rsn_ie[0], | ||
139 | adapter->secinfo.wep_enabled ? "e" : "d", | ||
140 | adapter->secinfo.WPAenabled ? "e" : "d", | ||
141 | adapter->secinfo.WPA2enabled ? "e" : "d", | ||
142 | adapter->scantable[index].privacy); | ||
143 | goto done; | ||
144 | } else if ( !adapter->secinfo.wep_enabled | ||
145 | && !adapter->secinfo.WPAenabled | ||
146 | && !adapter->secinfo.WPA2enabled | ||
147 | && (adapter->scantable[index].wpa_ie[0] != WPA_IE) | ||
148 | && (adapter->scantable[index].rsn_ie[0] != WPA2_IE) | ||
149 | && adapter->scantable[index].privacy) { | ||
150 | /* dynamic WEP enabled */ | ||
151 | lbs_deb_scan( | ||
152 | "is_network_compatible() dynamic WEP: index=%d " | ||
153 | "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n", | ||
154 | index, | ||
155 | adapter->scantable[index].wpa_ie[0], | ||
156 | adapter->scantable[index].rsn_ie[0], | ||
157 | adapter->scantable[index].privacy); | ||
158 | goto done; | ||
159 | } | ||
160 | 166 | ||
161 | /* security doesn't match */ | 167 | if ((matched = match_bss_no_security(&adapter->secinfo, bss))) { |
162 | lbs_deb_scan( | 168 | goto done; |
163 | "is_network_compatible() FAILED: index=%d wpa_ie=%#x " | 169 | } else if ((matched = match_bss_static_wep(&adapter->secinfo, bss))) { |
164 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n", | 170 | goto done; |
165 | index, | 171 | } else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) { |
166 | adapter->scantable[index].wpa_ie[0], | 172 | lbs_deb_scan( |
167 | adapter->scantable[index].rsn_ie[0], | 173 | "is_network_compatible() WPA: wpa_ie=%#x " |
174 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | ||
175 | "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0], | ||
168 | adapter->secinfo.wep_enabled ? "e" : "d", | 176 | adapter->secinfo.wep_enabled ? "e" : "d", |
169 | adapter->secinfo.WPAenabled ? "e" : "d", | 177 | adapter->secinfo.WPAenabled ? "e" : "d", |
170 | adapter->secinfo.WPA2enabled ? "e" : "d", | 178 | adapter->secinfo.WPA2enabled ? "e" : "d", |
171 | adapter->scantable[index].privacy); | 179 | bss->privacy); |
172 | index = -ECONNREFUSED; | 180 | goto done; |
181 | } else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) { | ||
182 | lbs_deb_scan( | ||
183 | "is_network_compatible() WPA2: wpa_ie=%#x " | ||
184 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " | ||
185 | "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0], | ||
186 | adapter->secinfo.wep_enabled ? "e" : "d", | ||
187 | adapter->secinfo.WPAenabled ? "e" : "d", | ||
188 | adapter->secinfo.WPA2enabled ? "e" : "d", | ||
189 | bss->privacy); | ||
190 | goto done; | ||
191 | } else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) { | ||
192 | lbs_deb_scan( | ||
193 | "is_network_compatible() dynamic WEP: " | ||
194 | "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n", | ||
195 | bss->wpa_ie[0], | ||
196 | bss->rsn_ie[0], | ||
197 | bss->privacy); | ||
173 | goto done; | 198 | goto done; |
174 | } | 199 | } |
175 | 200 | ||
176 | /* mode doesn't match */ | 201 | /* bss security settings don't match those configured on card */ |
177 | index = -ENETUNREACH; | 202 | lbs_deb_scan( |
203 | "is_network_compatible() FAILED: wpa_ie=%#x " | ||
204 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n", | ||
205 | bss->wpa_ie[0], bss->rsn_ie[0], | ||
206 | adapter->secinfo.wep_enabled ? "e" : "d", | ||
207 | adapter->secinfo.WPAenabled ? "e" : "d", | ||
208 | adapter->secinfo.WPA2enabled ? "e" : "d", | ||
209 | bss->privacy); | ||
178 | 210 | ||
179 | done: | 211 | done: |
180 | lbs_deb_leave_args(LBS_DEB_SCAN, "index %d", index); | 212 | lbs_deb_leave(LBS_DEB_SCAN); |
181 | return index; | 213 | return matched; |
182 | } | ||
183 | |||
184 | /** | ||
185 | * @brief This function validates a SSID as being able to be printed | ||
186 | * | ||
187 | * @param pssid SSID structure to validate | ||
188 | * | ||
189 | * @return TRUE or FALSE | ||
190 | */ | ||
191 | static u8 ssid_valid(struct WLAN_802_11_SSID *pssid) | ||
192 | { | ||
193 | int ssididx; | ||
194 | |||
195 | for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) { | ||
196 | if (!isprint(pssid->ssid[ssididx])) { | ||
197 | return 0; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | return 1; | ||
202 | } | 214 | } |
203 | 215 | ||
204 | /** | 216 | /** |
@@ -218,44 +230,35 @@ static u8 ssid_valid(struct WLAN_802_11_SSID *pssid) | |||
218 | static void wlan_scan_process_results(wlan_private * priv) | 230 | static void wlan_scan_process_results(wlan_private * priv) |
219 | { | 231 | { |
220 | wlan_adapter *adapter = priv->adapter; | 232 | wlan_adapter *adapter = priv->adapter; |
221 | int foundcurrent; | 233 | struct bss_descriptor * iter_bss; |
222 | int i; | ||
223 | |||
224 | foundcurrent = 0; | ||
225 | |||
226 | if (adapter->connect_status == libertas_connected) { | ||
227 | /* try to find the current BSSID in the new scan list */ | ||
228 | for (i = 0; i < adapter->numinscantable; i++) { | ||
229 | if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, | ||
230 | &adapter->curbssparams.ssid) && | ||
231 | !memcmp(adapter->curbssparams.bssid, | ||
232 | adapter->scantable[i].bssid, | ||
233 | ETH_ALEN)) { | ||
234 | foundcurrent = 1; | ||
235 | } | ||
236 | } | ||
237 | 234 | ||
238 | if (foundcurrent) { | 235 | mutex_lock(&adapter->lock); |
239 | /* Make a copy of current BSSID descriptor */ | 236 | |
240 | memcpy(&adapter->curbssparams.bssdescriptor, | 237 | if (adapter->connect_status != libertas_connected) |
241 | &adapter->scantable[i], | 238 | goto debug_print; |
242 | sizeof(adapter->curbssparams.bssdescriptor)); | 239 | |
243 | } | 240 | /* try to find the current BSSID in the scan list */ |
241 | list_for_each_entry (iter_bss, &adapter->network_list, list) { | ||
242 | if (libertas_SSID_cmp(&iter_bss->ssid, &adapter->curbssparams.ssid)) | ||
243 | continue; | ||
244 | if (memcmp(adapter->curbssparams.bssid, iter_bss->bssid, ETH_ALEN)) | ||
245 | continue; | ||
246 | /* Make a copy of current BSSID descriptor */ | ||
247 | memcpy(&adapter->curbssparams.bssdescriptor, iter_bss, | ||
248 | sizeof(struct bss_descriptor)); | ||
249 | break; | ||
244 | } | 250 | } |
245 | 251 | ||
246 | for (i = 0; i < adapter->numinscantable; i++) { | 252 | debug_print: |
247 | lbs_deb_scan("Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, " | 253 | list_for_each_entry (iter_bss, &adapter->network_list, list) { |
248 | "RSSI[%03d], SSID[%s]\n", | 254 | lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n", |
249 | i, | 255 | i++, |
250 | adapter->scantable[i].bssid[0], | 256 | iter_bss->bssid[0], iter_bss->bssid[1], iter_bss->bssid[2], |
251 | adapter->scantable[i].bssid[1], | 257 | iter_bss->bssid[3], iter_bss->bssid[4], iter_bss->bssid[5], |
252 | adapter->scantable[i].bssid[2], | 258 | (s32) iter_bss->rssi, iter_bss->ssid.ssid); |
253 | adapter->scantable[i].bssid[3], | ||
254 | adapter->scantable[i].bssid[4], | ||
255 | adapter->scantable[i].bssid[5], | ||
256 | (s32) adapter->scantable[i].rssi, | ||
257 | adapter->scantable[i].ssid.ssid); | ||
258 | } | 259 | } |
260 | |||
261 | mutex_unlock(&adapter->lock); | ||
259 | } | 262 | } |
260 | 263 | ||
261 | /** | 264 | /** |
@@ -798,9 +801,17 @@ int wlan_scan_networks(wlan_private * priv, | |||
798 | keeppreviousscan = 1; | 801 | keeppreviousscan = 1; |
799 | 802 | ||
800 | if (!keeppreviousscan) { | 803 | if (!keeppreviousscan) { |
801 | memset(adapter->scantable, 0x00, | 804 | struct bss_descriptor * iter_bss; |
802 | sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST); | 805 | struct bss_descriptor * safe; |
803 | adapter->numinscantable = 0; | 806 | |
807 | mutex_lock(&adapter->lock); | ||
808 | list_for_each_entry_safe (iter_bss, safe, | ||
809 | &adapter->network_list, list) { | ||
810 | list_move_tail (&iter_bss->list, | ||
811 | &adapter->network_free_list); | ||
812 | clear_bss_descriptor(iter_bss); | ||
813 | } | ||
814 | mutex_unlock(&adapter->lock); | ||
804 | } | 815 | } |
805 | 816 | ||
806 | /* Keep the data path active if we are only scanning our current channel */ | 817 | /* Keep the data path active if we are only scanning our current channel */ |
@@ -903,12 +914,12 @@ void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, | |||
903 | * response or beacon from the scan command. Record information as needed | 914 | * response or beacon from the scan command. Record information as needed |
904 | * in the scan table struct bss_descriptor for that entry. | 915 | * in the scan table struct bss_descriptor for that entry. |
905 | * | 916 | * |
906 | * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry | 917 | * @param bss Output parameter: Pointer to the BSS Entry |
907 | * | 918 | * |
908 | * @return 0 or -1 | 919 | * @return 0 or -1 |
909 | */ | 920 | */ |
910 | static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | 921 | static int libertas_process_bss(struct bss_descriptor * bss, |
911 | u8 ** pbeaconinfo, int *bytesleft) | 922 | u8 ** pbeaconinfo, int *bytesleft) |
912 | { | 923 | { |
913 | enum ieeetypes_elementid elemID; | 924 | enum ieeetypes_elementid elemID; |
914 | struct ieeetypes_fhparamset *pFH; | 925 | struct ieeetypes_fhparamset *pFH; |
@@ -963,17 +974,16 @@ static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | |||
963 | 974 | ||
964 | bytesleftforcurrentbeacon = beaconsize; | 975 | bytesleftforcurrentbeacon = beaconsize; |
965 | 976 | ||
966 | memcpy(pBSSEntry->bssid, pcurrentptr, ETH_ALEN); | 977 | memcpy(bss->bssid, pcurrentptr, ETH_ALEN); |
967 | lbs_deb_scan("InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n", | 978 | lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", |
968 | pBSSEntry->bssid[0], pBSSEntry->bssid[1], | 979 | bss->bssid[0], bss->bssid[1], bss->bssid[2], |
969 | pBSSEntry->bssid[2], pBSSEntry->bssid[3], | 980 | bss->bssid[3], bss->bssid[4], bss->bssid[5]); |
970 | pBSSEntry->bssid[4], pBSSEntry->bssid[5]); | ||
971 | 981 | ||
972 | pcurrentptr += ETH_ALEN; | 982 | pcurrentptr += ETH_ALEN; |
973 | bytesleftforcurrentbeacon -= ETH_ALEN; | 983 | bytesleftforcurrentbeacon -= ETH_ALEN; |
974 | 984 | ||
975 | if (bytesleftforcurrentbeacon < 12) { | 985 | if (bytesleftforcurrentbeacon < 12) { |
976 | lbs_deb_scan("InterpretIE: Not enough bytes left\n"); | 986 | lbs_deb_scan("process_bss: Not enough bytes left\n"); |
977 | return -1; | 987 | return -1; |
978 | } | 988 | } |
979 | 989 | ||
@@ -983,51 +993,51 @@ static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | |||
983 | */ | 993 | */ |
984 | 994 | ||
985 | /* RSSI is 1 byte long */ | 995 | /* RSSI is 1 byte long */ |
986 | pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr)); | 996 | bss->rssi = le32_to_cpu((long)(*pcurrentptr)); |
987 | lbs_deb_scan("InterpretIE: RSSI=%02X\n", *pcurrentptr); | 997 | lbs_deb_scan("process_bss: RSSI=%02X\n", *pcurrentptr); |
988 | pcurrentptr += 1; | 998 | pcurrentptr += 1; |
989 | bytesleftforcurrentbeacon -= 1; | 999 | bytesleftforcurrentbeacon -= 1; |
990 | 1000 | ||
991 | /* time stamp is 8 bytes long */ | 1001 | /* time stamp is 8 bytes long */ |
992 | memcpy(fixedie.timestamp, pcurrentptr, 8); | 1002 | memcpy(fixedie.timestamp, pcurrentptr, 8); |
993 | memcpy(pBSSEntry->timestamp, pcurrentptr, 8); | 1003 | memcpy(bss->timestamp, pcurrentptr, 8); |
994 | pcurrentptr += 8; | 1004 | pcurrentptr += 8; |
995 | bytesleftforcurrentbeacon -= 8; | 1005 | bytesleftforcurrentbeacon -= 8; |
996 | 1006 | ||
997 | /* beacon interval is 2 bytes long */ | 1007 | /* beacon interval is 2 bytes long */ |
998 | memcpy(&fixedie.beaconinterval, pcurrentptr, 2); | 1008 | memcpy(&fixedie.beaconinterval, pcurrentptr, 2); |
999 | pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval); | 1009 | bss->beaconperiod = le16_to_cpu(fixedie.beaconinterval); |
1000 | pcurrentptr += 2; | 1010 | pcurrentptr += 2; |
1001 | bytesleftforcurrentbeacon -= 2; | 1011 | bytesleftforcurrentbeacon -= 2; |
1002 | 1012 | ||
1003 | /* capability information is 2 bytes long */ | 1013 | /* capability information is 2 bytes long */ |
1004 | memcpy(&fixedie.capabilities, pcurrentptr, 2); | 1014 | memcpy(&fixedie.capabilities, pcurrentptr, 2); |
1005 | lbs_deb_scan("InterpretIE: fixedie.capabilities=0x%X\n", | 1015 | lbs_deb_scan("process_bss: fixedie.capabilities=0x%X\n", |
1006 | fixedie.capabilities); | 1016 | fixedie.capabilities); |
1007 | fixedie.capabilities = le16_to_cpu(fixedie.capabilities); | 1017 | fixedie.capabilities = le16_to_cpu(fixedie.capabilities); |
1008 | pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities; | 1018 | pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities; |
1009 | memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo)); | 1019 | memcpy(&bss->cap, pcap, sizeof(struct ieeetypes_capinfo)); |
1010 | pcurrentptr += 2; | 1020 | pcurrentptr += 2; |
1011 | bytesleftforcurrentbeacon -= 2; | 1021 | bytesleftforcurrentbeacon -= 2; |
1012 | 1022 | ||
1013 | /* rest of the current buffer are IE's */ | 1023 | /* rest of the current buffer are IE's */ |
1014 | lbs_deb_scan("InterpretIE: IElength for this AP = %d\n", | 1024 | lbs_deb_scan("process_bss: IE length for this AP = %d\n", |
1015 | bytesleftforcurrentbeacon); | 1025 | bytesleftforcurrentbeacon); |
1016 | 1026 | ||
1017 | lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr, | 1027 | lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr, |
1018 | bytesleftforcurrentbeacon); | 1028 | bytesleftforcurrentbeacon); |
1019 | 1029 | ||
1020 | if (pcap->privacy) { | 1030 | if (pcap->privacy) { |
1021 | lbs_deb_scan("InterpretIE: AP WEP enabled\n"); | 1031 | lbs_deb_scan("process_bss: AP WEP enabled\n"); |
1022 | pBSSEntry->privacy = wlan802_11privfilter8021xWEP; | 1032 | bss->privacy = wlan802_11privfilter8021xWEP; |
1023 | } else { | 1033 | } else { |
1024 | pBSSEntry->privacy = wlan802_11privfilteracceptall; | 1034 | bss->privacy = wlan802_11privfilteracceptall; |
1025 | } | 1035 | } |
1026 | 1036 | ||
1027 | if (pcap->ibss == 1) { | 1037 | if (pcap->ibss == 1) { |
1028 | pBSSEntry->mode = IW_MODE_ADHOC; | 1038 | bss->mode = IW_MODE_ADHOC; |
1029 | } else { | 1039 | } else { |
1030 | pBSSEntry->mode = IW_MODE_INFRA; | 1040 | bss->mode = IW_MODE_INFRA; |
1031 | } | 1041 | } |
1032 | 1042 | ||
1033 | /* process variable IE */ | 1043 | /* process variable IE */ |
@@ -1036,84 +1046,67 @@ static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | |||
1036 | elemlen = *((u8 *) pcurrentptr + 1); | 1046 | elemlen = *((u8 *) pcurrentptr + 1); |
1037 | 1047 | ||
1038 | if (bytesleftforcurrentbeacon < elemlen) { | 1048 | if (bytesleftforcurrentbeacon < elemlen) { |
1039 | lbs_deb_scan("InterpretIE: error in processing IE, " | 1049 | lbs_deb_scan("process_bss: error in processing IE, " |
1040 | "bytes left < IE length\n"); | 1050 | "bytes left < IE length\n"); |
1041 | bytesleftforcurrentbeacon = 0; | 1051 | bytesleftforcurrentbeacon = 0; |
1042 | continue; | 1052 | continue; |
1043 | } | 1053 | } |
1044 | 1054 | ||
1045 | switch (elemID) { | 1055 | switch (elemID) { |
1046 | |||
1047 | case SSID: | 1056 | case SSID: |
1048 | pBSSEntry->ssid.ssidlength = elemlen; | 1057 | bss->ssid.ssidlength = elemlen; |
1049 | memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2), | 1058 | memcpy(bss->ssid.ssid, (pcurrentptr + 2), elemlen); |
1050 | elemlen); | 1059 | lbs_deb_scan("ssid '%s'\n", bss->ssid.ssid); |
1051 | lbs_deb_scan("ssid '%s'\n", pBSSEntry->ssid.ssid); | ||
1052 | break; | 1060 | break; |
1053 | 1061 | ||
1054 | case SUPPORTED_RATES: | 1062 | case SUPPORTED_RATES: |
1055 | memcpy(pBSSEntry->datarates, (pcurrentptr + 2), | 1063 | memcpy(bss->datarates, (pcurrentptr + 2), elemlen); |
1056 | elemlen); | 1064 | memmove(bss->libertas_supported_rates, (pcurrentptr + 2), |
1057 | memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2), | ||
1058 | elemlen); | 1065 | elemlen); |
1059 | ratesize = elemlen; | 1066 | ratesize = elemlen; |
1060 | founddatarateie = 1; | 1067 | founddatarateie = 1; |
1061 | break; | 1068 | break; |
1062 | 1069 | ||
1063 | case EXTRA_IE: | 1070 | case EXTRA_IE: |
1064 | lbs_deb_scan("InterpretIE: EXTRA_IE Found!\n"); | 1071 | lbs_deb_scan("process_bss: EXTRA_IE Found!\n"); |
1065 | pBSSEntry->extra_ie = 1; | ||
1066 | break; | 1072 | break; |
1067 | 1073 | ||
1068 | case FH_PARAM_SET: | 1074 | case FH_PARAM_SET: |
1069 | pFH = (struct ieeetypes_fhparamset *) pcurrentptr; | 1075 | pFH = (struct ieeetypes_fhparamset *) pcurrentptr; |
1070 | memmove(&pBSSEntry->phyparamset.fhparamset, pFH, | 1076 | memmove(&bss->phyparamset.fhparamset, pFH, |
1071 | sizeof(struct ieeetypes_fhparamset)); | 1077 | sizeof(struct ieeetypes_fhparamset)); |
1072 | pBSSEntry->phyparamset.fhparamset.dwelltime | 1078 | bss->phyparamset.fhparamset.dwelltime |
1073 | = | 1079 | = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime); |
1074 | le16_to_cpu(pBSSEntry->phyparamset.fhparamset. | ||
1075 | dwelltime); | ||
1076 | break; | 1080 | break; |
1077 | 1081 | ||
1078 | case DS_PARAM_SET: | 1082 | case DS_PARAM_SET: |
1079 | pDS = (struct ieeetypes_dsparamset *) pcurrentptr; | 1083 | pDS = (struct ieeetypes_dsparamset *) pcurrentptr; |
1080 | 1084 | bss->channel = pDS->currentchan; | |
1081 | pBSSEntry->channel = pDS->currentchan; | 1085 | memcpy(&bss->phyparamset.dsparamset, pDS, |
1082 | |||
1083 | memcpy(&pBSSEntry->phyparamset.dsparamset, pDS, | ||
1084 | sizeof(struct ieeetypes_dsparamset)); | 1086 | sizeof(struct ieeetypes_dsparamset)); |
1085 | break; | 1087 | break; |
1086 | 1088 | ||
1087 | case CF_PARAM_SET: | 1089 | case CF_PARAM_SET: |
1088 | pCF = (struct ieeetypes_cfparamset *) pcurrentptr; | 1090 | pCF = (struct ieeetypes_cfparamset *) pcurrentptr; |
1089 | 1091 | memcpy(&bss->ssparamset.cfparamset, pCF, | |
1090 | memcpy(&pBSSEntry->ssparamset.cfparamset, pCF, | ||
1091 | sizeof(struct ieeetypes_cfparamset)); | 1092 | sizeof(struct ieeetypes_cfparamset)); |
1092 | break; | 1093 | break; |
1093 | 1094 | ||
1094 | case IBSS_PARAM_SET: | 1095 | case IBSS_PARAM_SET: |
1095 | pibss = (struct ieeetypes_ibssparamset *) pcurrentptr; | 1096 | pibss = (struct ieeetypes_ibssparamset *) pcurrentptr; |
1096 | pBSSEntry->atimwindow = | 1097 | bss->atimwindow = le32_to_cpu(pibss->atimwindow); |
1097 | le32_to_cpu(pibss->atimwindow); | 1098 | memmove(&bss->ssparamset.ibssparamset, pibss, |
1098 | |||
1099 | memmove(&pBSSEntry->ssparamset.ibssparamset, pibss, | ||
1100 | sizeof(struct ieeetypes_ibssparamset)); | 1099 | sizeof(struct ieeetypes_ibssparamset)); |
1101 | 1100 | bss->ssparamset.ibssparamset.atimwindow | |
1102 | pBSSEntry->ssparamset.ibssparamset.atimwindow | 1101 | = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow); |
1103 | = | ||
1104 | le16_to_cpu(pBSSEntry->ssparamset.ibssparamset. | ||
1105 | atimwindow); | ||
1106 | break; | 1102 | break; |
1107 | 1103 | ||
1108 | /* Handle Country Info IE */ | 1104 | /* Handle Country Info IE */ |
1109 | case COUNTRY_INFO: | 1105 | case COUNTRY_INFO: |
1110 | pcountryinfo = | 1106 | pcountryinfo = (struct ieeetypes_countryinfoset *) pcurrentptr; |
1111 | (struct ieeetypes_countryinfoset *) pcurrentptr; | 1107 | if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) |
1112 | |||
1113 | if (pcountryinfo->len < | ||
1114 | sizeof(pcountryinfo->countrycode) | ||
1115 | || pcountryinfo->len > 254) { | 1108 | || pcountryinfo->len > 254) { |
1116 | lbs_deb_scan("InterpretIE: 11D- Err " | 1109 | lbs_deb_scan("process_bss: 11D- Err " |
1117 | "CountryInfo len =%d min=%zd max=254\n", | 1110 | "CountryInfo len =%d min=%zd max=254\n", |
1118 | pcountryinfo->len, | 1111 | pcountryinfo->len, |
1119 | sizeof(pcountryinfo->countrycode)); | 1112 | sizeof(pcountryinfo->countrycode)); |
@@ -1121,9 +1114,9 @@ static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | |||
1121 | goto done; | 1114 | goto done; |
1122 | } | 1115 | } |
1123 | 1116 | ||
1124 | memcpy(&pBSSEntry->countryinfo, | 1117 | memcpy(&bss->countryinfo, |
1125 | pcountryinfo, pcountryinfo->len + 2); | 1118 | pcountryinfo, pcountryinfo->len + 2); |
1126 | lbs_dbg_hex("InterpretIE: 11D- CountryInfo:", | 1119 | lbs_dbg_hex("process_bss: 11D- CountryInfo:", |
1127 | (u8 *) pcountryinfo, | 1120 | (u8 *) pcountryinfo, |
1128 | (u32) (pcountryinfo->len + 2)); | 1121 | (u32) (pcountryinfo->len + 2)); |
1129 | break; | 1122 | break; |
@@ -1143,12 +1136,10 @@ static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | |||
1143 | bytestocopy = elemlen; | 1136 | bytestocopy = elemlen; |
1144 | } | 1137 | } |
1145 | 1138 | ||
1146 | pRate = (u8 *) pBSSEntry->datarates; | 1139 | pRate = (u8 *) bss->datarates; |
1147 | pRate += ratesize; | 1140 | pRate += ratesize; |
1148 | memmove(pRate, (pcurrentptr + 2), bytestocopy); | 1141 | memmove(pRate, (pcurrentptr + 2), bytestocopy); |
1149 | 1142 | pRate = (u8 *) bss->libertas_supported_rates; | |
1150 | pRate = (u8 *) pBSSEntry->libertas_supported_rates; | ||
1151 | |||
1152 | pRate += ratesize; | 1143 | pRate += ratesize; |
1153 | memmove(pRate, (pcurrentptr + 2), bytestocopy); | 1144 | memmove(pRate, (pcurrentptr + 2), bytestocopy); |
1154 | } | 1145 | } |
@@ -1161,24 +1152,17 @@ static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | |||
1161 | if (memcmp(pIe->oui, oui01, sizeof(oui01))) | 1152 | if (memcmp(pIe->oui, oui01, sizeof(oui01))) |
1162 | break; | 1153 | break; |
1163 | 1154 | ||
1164 | pBSSEntry->wpa_ie_len = min_t(size_t, | 1155 | bss->wpa_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES, |
1165 | elemlen + IE_ID_LEN_FIELDS_BYTES, | 1156 | MAX_WPA_IE_LEN); |
1166 | sizeof(pBSSEntry->wpa_ie)); | 1157 | memcpy(bss->wpa_ie, pcurrentptr, bss->wpa_ie_len); |
1167 | memcpy(pBSSEntry->wpa_ie, pcurrentptr, | 1158 | lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elemlen); |
1168 | pBSSEntry->wpa_ie_len); | ||
1169 | lbs_dbg_hex("InterpretIE: Resp WPA_IE", | ||
1170 | pBSSEntry->wpa_ie, elemlen); | ||
1171 | break; | 1159 | break; |
1172 | case WPA2_IE: | 1160 | case WPA2_IE: |
1173 | pIe = (struct IE_WPA *)pcurrentptr; | 1161 | pIe = (struct IE_WPA *)pcurrentptr; |
1174 | 1162 | bss->rsn_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES, | |
1175 | pBSSEntry->rsn_ie_len = min_t(size_t, | 1163 | MAX_WPA_IE_LEN); |
1176 | elemlen + IE_ID_LEN_FIELDS_BYTES, | 1164 | memcpy(bss->rsn_ie, pcurrentptr, bss->rsn_ie_len); |
1177 | sizeof(pBSSEntry->rsn_ie)); | 1165 | lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elemlen); |
1178 | memcpy(pBSSEntry->rsn_ie, pcurrentptr, | ||
1179 | pBSSEntry->rsn_ie_len); | ||
1180 | lbs_dbg_hex("InterpretIE: Resp WPA2_IE", | ||
1181 | pBSSEntry->rsn_ie, elemlen); | ||
1182 | break; | 1166 | break; |
1183 | case TIM: | 1167 | case TIM: |
1184 | break; | 1168 | break; |
@@ -1193,6 +1177,10 @@ static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | |||
1193 | bytesleftforcurrentbeacon -= (elemlen + 2); | 1177 | bytesleftforcurrentbeacon -= (elemlen + 2); |
1194 | 1178 | ||
1195 | } /* while (bytesleftforcurrentbeacon > 2) */ | 1179 | } /* while (bytesleftforcurrentbeacon > 2) */ |
1180 | |||
1181 | /* Timestamp */ | ||
1182 | bss->last_scanned = jiffies; | ||
1183 | |||
1196 | ret = 0; | 1184 | ret = 0; |
1197 | 1185 | ||
1198 | done: | 1186 | done: |
@@ -1228,38 +1216,41 @@ int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *s | |||
1228 | * | 1216 | * |
1229 | * @return index in BSSID list, or error return code (< 0) | 1217 | * @return index in BSSID list, or error return code (< 0) |
1230 | */ | 1218 | */ |
1231 | int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode) | 1219 | struct bss_descriptor * libertas_find_BSSID_in_list(wlan_adapter * adapter, |
1220 | u8 * bssid, u8 mode) | ||
1232 | { | 1221 | { |
1233 | int ret = -ENETUNREACH; | 1222 | struct bss_descriptor * iter_bss; |
1234 | int i; | 1223 | struct bss_descriptor * found_bss = NULL; |
1235 | 1224 | ||
1236 | if (!bssid) | 1225 | if (!bssid) |
1237 | return -EFAULT; | 1226 | return NULL; |
1238 | 1227 | ||
1239 | lbs_deb_scan("FindBSSID: Num of BSSIDs = %d\n", | 1228 | lbs_dbg_hex("libertas_find_BSSID_in_list: looking for ", |
1240 | adapter->numinscantable); | 1229 | bssid, ETH_ALEN); |
1241 | 1230 | ||
1242 | /* Look through the scan table for a compatible match. The ret return | 1231 | /* Look through the scan table for a compatible match. The loop will |
1243 | * variable will be equal to the index in the scan table (greater | 1232 | * continue past a matched bssid that is not compatible in case there |
1244 | * than zero) if the network is compatible. The loop will continue | 1233 | * is an AP with multiple SSIDs assigned to the same BSSID |
1245 | * past a matched bssid that is not compatible in case there is an | ||
1246 | * AP with multiple SSIDs assigned to the same BSSID | ||
1247 | */ | 1234 | */ |
1248 | for (i = 0; ret < 0 && i < adapter->numinscantable; i++) { | 1235 | mutex_lock(&adapter->lock); |
1249 | if (!memcmp(adapter->scantable[i].bssid, bssid, ETH_ALEN)) { | 1236 | list_for_each_entry (iter_bss, &adapter->network_list, list) { |
1250 | switch (mode) { | 1237 | if (memcmp(iter_bss->bssid, bssid, ETH_ALEN)) |
1251 | case IW_MODE_INFRA: | 1238 | continue; /* bssid doesn't match */ |
1252 | case IW_MODE_ADHOC: | 1239 | switch (mode) { |
1253 | ret = is_network_compatible(adapter, i, mode); | 1240 | case IW_MODE_INFRA: |
1254 | break; | 1241 | case IW_MODE_ADHOC: |
1255 | default: | 1242 | if (!is_network_compatible(adapter, iter_bss, mode)) |
1256 | ret = i; | ||
1257 | break; | 1243 | break; |
1258 | } | 1244 | found_bss = iter_bss; |
1245 | break; | ||
1246 | default: | ||
1247 | found_bss = iter_bss; | ||
1248 | break; | ||
1259 | } | 1249 | } |
1260 | } | 1250 | } |
1251 | mutex_unlock(&adapter->lock); | ||
1261 | 1252 | ||
1262 | return ret; | 1253 | return found_bss; |
1263 | } | 1254 | } |
1264 | 1255 | ||
1265 | /** | 1256 | /** |
@@ -1272,60 +1263,56 @@ int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, u8 mode) | |||
1272 | * | 1263 | * |
1273 | * @return index in BSSID list | 1264 | * @return index in BSSID list |
1274 | */ | 1265 | */ |
1275 | int libertas_find_SSID_in_list(wlan_adapter * adapter, | 1266 | struct bss_descriptor * libertas_find_SSID_in_list(wlan_adapter * adapter, |
1276 | struct WLAN_802_11_SSID *ssid, u8 * bssid, u8 mode) | 1267 | struct WLAN_802_11_SSID *ssid, u8 * bssid, u8 mode) |
1277 | { | 1268 | { |
1278 | int net = -ENETUNREACH; | ||
1279 | u8 bestrssi = 0; | 1269 | u8 bestrssi = 0; |
1280 | int i; | 1270 | struct bss_descriptor * iter_bss = NULL; |
1281 | int j; | 1271 | struct bss_descriptor * found_bss = NULL; |
1272 | struct bss_descriptor * tmp_oldest = NULL; | ||
1282 | 1273 | ||
1283 | lbs_deb_scan("Num of Entries in Table = %d\n", adapter->numinscantable); | 1274 | mutex_lock(&adapter->lock); |
1284 | 1275 | ||
1285 | for (i = 0; i < adapter->numinscantable; i++) { | 1276 | list_for_each_entry (iter_bss, &adapter->network_list, list) { |
1286 | if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) && | 1277 | if ( !tmp_oldest |
1287 | (!bssid || | 1278 | || (iter_bss->last_scanned < tmp_oldest->last_scanned)) |
1288 | !memcmp(adapter->scantable[i].bssid, bssid, ETH_ALEN))) { | 1279 | tmp_oldest = iter_bss; |
1289 | switch (mode) { | 1280 | |
1290 | case IW_MODE_INFRA: | 1281 | if (libertas_SSID_cmp(&iter_bss->ssid, ssid) != 0) |
1291 | case IW_MODE_ADHOC: | 1282 | continue; /* ssid doesn't match */ |
1292 | j = is_network_compatible(adapter, i, mode); | 1283 | if (bssid && memcmp(iter_bss->bssid, bssid, ETH_ALEN) != 0) |
1293 | 1284 | continue; /* bssid doesn't match */ | |
1294 | if (j >= 0) { | 1285 | |
1295 | if (bssid) { | 1286 | switch (mode) { |
1296 | return i; | 1287 | case IW_MODE_INFRA: |
1297 | } | 1288 | case IW_MODE_ADHOC: |
1298 | 1289 | if (!is_network_compatible(adapter, iter_bss, mode)) | |
1299 | if (SCAN_RSSI | ||
1300 | (adapter->scantable[i].rssi) | ||
1301 | > bestrssi) { | ||
1302 | bestrssi = | ||
1303 | SCAN_RSSI(adapter-> | ||
1304 | scantable[i]. | ||
1305 | rssi); | ||
1306 | net = i; | ||
1307 | } | ||
1308 | } else { | ||
1309 | if (net == -ENETUNREACH) { | ||
1310 | net = j; | ||
1311 | } | ||
1312 | } | ||
1313 | break; | ||
1314 | case IW_MODE_AUTO: | ||
1315 | default: | ||
1316 | if (SCAN_RSSI(adapter->scantable[i].rssi) | ||
1317 | > bestrssi) { | ||
1318 | bestrssi = | ||
1319 | SCAN_RSSI(adapter->scantable[i]. | ||
1320 | rssi); | ||
1321 | net = i; | ||
1322 | } | ||
1323 | break; | 1290 | break; |
1291 | |||
1292 | if (bssid) { | ||
1293 | /* Found requested BSSID */ | ||
1294 | found_bss = iter_bss; | ||
1295 | goto out; | ||
1296 | } | ||
1297 | |||
1298 | if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { | ||
1299 | bestrssi = SCAN_RSSI(iter_bss->rssi); | ||
1300 | found_bss = iter_bss; | ||
1301 | } | ||
1302 | break; | ||
1303 | case IW_MODE_AUTO: | ||
1304 | default: | ||
1305 | if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { | ||
1306 | bestrssi = SCAN_RSSI(iter_bss->rssi); | ||
1307 | found_bss = iter_bss; | ||
1324 | } | 1308 | } |
1309 | break; | ||
1325 | } | 1310 | } |
1326 | } | 1311 | } |
1327 | 1312 | ||
1328 | return net; | 1313 | out: |
1314 | mutex_unlock(&adapter->lock); | ||
1315 | return found_bss; | ||
1329 | } | 1316 | } |
1330 | 1317 | ||
1331 | /** | 1318 | /** |
@@ -1338,43 +1325,38 @@ int libertas_find_SSID_in_list(wlan_adapter * adapter, | |||
1338 | * | 1325 | * |
1339 | * @return index in BSSID list | 1326 | * @return index in BSSID list |
1340 | */ | 1327 | */ |
1341 | int libertas_find_best_SSID_in_list(wlan_adapter * adapter, u8 mode) | 1328 | struct bss_descriptor * libertas_find_best_SSID_in_list(wlan_adapter * adapter, |
1329 | u8 mode) | ||
1342 | { | 1330 | { |
1343 | int bestnet = -ENETUNREACH; | ||
1344 | u8 bestrssi = 0; | 1331 | u8 bestrssi = 0; |
1345 | int i; | 1332 | struct bss_descriptor * iter_bss; |
1346 | 1333 | struct bss_descriptor * best_bss = NULL; | |
1347 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1348 | 1334 | ||
1349 | lbs_deb_scan("Num of BSSIDs = %d\n", adapter->numinscantable); | 1335 | mutex_lock(&adapter->lock); |
1350 | 1336 | ||
1351 | for (i = 0; i < adapter->numinscantable; i++) { | 1337 | list_for_each_entry (iter_bss, &adapter->network_list, list) { |
1352 | switch (mode) { | 1338 | switch (mode) { |
1353 | case IW_MODE_INFRA: | 1339 | case IW_MODE_INFRA: |
1354 | case IW_MODE_ADHOC: | 1340 | case IW_MODE_ADHOC: |
1355 | if (is_network_compatible(adapter, i, mode) >= 0) { | 1341 | if (!is_network_compatible(adapter, iter_bss, mode)) |
1356 | if (SCAN_RSSI(adapter->scantable[i].rssi) > | 1342 | break; |
1357 | bestrssi) { | 1343 | if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) |
1358 | bestrssi = | 1344 | break; |
1359 | SCAN_RSSI(adapter->scantable[i]. | 1345 | bestrssi = SCAN_RSSI(iter_bss->rssi); |
1360 | rssi); | 1346 | best_bss = iter_bss; |
1361 | bestnet = i; | ||
1362 | } | ||
1363 | } | ||
1364 | break; | 1347 | break; |
1365 | case IW_MODE_AUTO: | 1348 | case IW_MODE_AUTO: |
1366 | default: | 1349 | default: |
1367 | if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) { | 1350 | if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) |
1368 | bestrssi = | 1351 | break; |
1369 | SCAN_RSSI(adapter->scantable[i].rssi); | 1352 | bestrssi = SCAN_RSSI(iter_bss->rssi); |
1370 | bestnet = i; | 1353 | best_bss = iter_bss; |
1371 | } | ||
1372 | break; | 1354 | break; |
1373 | } | 1355 | } |
1374 | } | 1356 | } |
1375 | 1357 | ||
1376 | lbs_deb_leave_args(LBS_DEB_SCAN, "bestnet %d", bestnet); | 1358 | mutex_unlock(&adapter->lock); |
1377 | return bestnet; | 1359 | return best_bss; |
1378 | } | 1360 | } |
1379 | 1361 | ||
1380 | /** | 1362 | /** |
@@ -1386,39 +1368,30 @@ int libertas_find_best_SSID_in_list(wlan_adapter * adapter, u8 mode) | |||
1386 | * @return 0--success, otherwise--fail | 1368 | * @return 0--success, otherwise--fail |
1387 | */ | 1369 | */ |
1388 | int libertas_find_best_network_SSID(wlan_private * priv, | 1370 | int libertas_find_best_network_SSID(wlan_private * priv, |
1389 | struct WLAN_802_11_SSID *pSSID, | 1371 | struct WLAN_802_11_SSID *ssid, |
1390 | u8 preferred_mode, u8 *out_mode) | 1372 | u8 preferred_mode, u8 *out_mode) |
1391 | { | 1373 | { |
1392 | wlan_adapter *adapter = priv->adapter; | 1374 | wlan_adapter *adapter = priv->adapter; |
1393 | int ret = 0; | 1375 | int ret = -1; |
1394 | struct bss_descriptor *preqbssid; | 1376 | struct bss_descriptor * found; |
1395 | int i; | ||
1396 | 1377 | ||
1397 | lbs_deb_enter(LBS_DEB_ASSOC); | 1378 | lbs_deb_enter(LBS_DEB_ASSOC); |
1398 | 1379 | ||
1399 | memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID)); | 1380 | memset(ssid, 0, sizeof(struct WLAN_802_11_SSID)); |
1400 | 1381 | ||
1401 | wlan_scan_networks(priv, NULL, 1); | 1382 | wlan_scan_networks(priv, NULL, 1); |
1402 | if (adapter->surpriseremoved) | 1383 | if (adapter->surpriseremoved) |
1403 | return -1; | 1384 | return -1; |
1404 | wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); | ||
1405 | |||
1406 | i = libertas_find_best_SSID_in_list(adapter, preferred_mode); | ||
1407 | if (i < 0) { | ||
1408 | ret = -1; | ||
1409 | goto out; | ||
1410 | } | ||
1411 | 1385 | ||
1412 | preqbssid = &adapter->scantable[i]; | 1386 | wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); |
1413 | memcpy(pSSID, &preqbssid->ssid, | ||
1414 | sizeof(struct WLAN_802_11_SSID)); | ||
1415 | *out_mode = preqbssid->mode; | ||
1416 | 1387 | ||
1417 | if (!pSSID->ssidlength) { | 1388 | found = libertas_find_best_SSID_in_list(adapter, preferred_mode); |
1418 | ret = -1; | 1389 | if (found && (found->ssid.ssidlength > 0)) { |
1390 | memcpy(ssid, &found->ssid, sizeof(struct WLAN_802_11_SSID)); | ||
1391 | *out_mode = found->mode; | ||
1392 | ret = 0; | ||
1419 | } | 1393 | } |
1420 | 1394 | ||
1421 | out: | ||
1422 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | 1395 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); |
1423 | return ret; | 1396 | return ret; |
1424 | } | 1397 | } |
@@ -1520,285 +1493,206 @@ int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppr | |||
1520 | return 0; | 1493 | return 0; |
1521 | } | 1494 | } |
1522 | 1495 | ||
1523 | /** | 1496 | static inline char *libertas_translate_scan(wlan_private *priv, |
1524 | * @brief Retrieve the scan table entries via wireless tools IOCTL call | 1497 | char *start, char *stop, |
1525 | * | 1498 | struct bss_descriptor *bss) |
1526 | * @param dev A pointer to net_device structure | ||
1527 | * @param info A pointer to iw_request_info structure | ||
1528 | * @param dwrq A pointer to iw_point structure | ||
1529 | * @param extra A pointer to extra data buf | ||
1530 | * | ||
1531 | * @return 0 --success, otherwise fail | ||
1532 | */ | ||
1533 | int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, | ||
1534 | struct iw_point *dwrq, char *extra) | ||
1535 | { | 1499 | { |
1536 | wlan_private *priv = dev->priv; | ||
1537 | wlan_adapter *adapter = priv->adapter; | 1500 | wlan_adapter *adapter = priv->adapter; |
1538 | int ret = 0; | ||
1539 | char *current_ev = extra; | ||
1540 | char *end_buf = extra + IW_SCAN_MAX_DATA; | ||
1541 | struct chan_freq_power *cfp; | 1501 | struct chan_freq_power *cfp; |
1542 | struct bss_descriptor *pscantable; | ||
1543 | char *current_val; /* For rates */ | 1502 | char *current_val; /* For rates */ |
1544 | struct iw_event iwe; /* Temporary buffer */ | 1503 | struct iw_event iwe; /* Temporary buffer */ |
1545 | int i; | ||
1546 | int j; | 1504 | int j; |
1547 | int rate; | 1505 | int ret; |
1548 | #define PERFECT_RSSI ((u8)50) | 1506 | #define PERFECT_RSSI ((u8)50) |
1549 | #define WORST_RSSI ((u8)0) | 1507 | #define WORST_RSSI ((u8)0) |
1550 | #define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) | 1508 | #define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) |
1551 | u8 rssi; | 1509 | u8 rssi; |
1552 | 1510 | ||
1553 | u8 buf[16 + 256 * 2]; | 1511 | cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel); |
1554 | u8 *ptr; | 1512 | if (!cfp) { |
1555 | 1513 | lbs_deb_scan("Invalid channel number %d\n", bss->channel); | |
1556 | lbs_deb_enter(LBS_DEB_ASSOC); | 1514 | return NULL; |
1557 | |||
1558 | /* | ||
1559 | * if there's either commands in the queue or one being | ||
1560 | * processed return -EAGAIN for iwlist to retry later. | ||
1561 | */ | ||
1562 | if (adapter->nr_cmd_pending) | ||
1563 | return -EAGAIN; | ||
1564 | |||
1565 | if (adapter->last_scanned_channel) { | ||
1566 | wlan_scan_networks(priv, NULL, 0); | ||
1567 | return -EAGAIN; | ||
1568 | } | 1515 | } |
1569 | 1516 | ||
1570 | if (adapter->connect_status == libertas_connected) | 1517 | /* First entry *MUST* be the AP BSSID */ |
1571 | lbs_deb_scan("current ssid '%s'\n", | 1518 | iwe.cmd = SIOCGIWAP; |
1572 | adapter->curbssparams.ssid.ssid); | 1519 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; |
1573 | 1520 | memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN); | |
1574 | lbs_deb_scan("Scan: Get: numinscantable = %d\n", | 1521 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); |
1575 | adapter->numinscantable); | 1522 | |
1576 | 1523 | /* SSID */ | |
1577 | /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. | 1524 | iwe.cmd = SIOCGIWESSID; |
1578 | * The new API using SIOCGIWSCAN is only limited by buffer size | 1525 | iwe.u.data.flags = 1; |
1579 | * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes | 1526 | iwe.u.data.length = min(bss->ssid.ssidlength, (u32) IW_ESSID_MAX_SIZE); |
1580 | * which is 4096. | 1527 | start = iwe_stream_add_point(start, stop, &iwe, bss->ssid.ssid); |
1581 | */ | 1528 | |
1582 | for (i = 0; i < adapter->numinscantable; i++) { | 1529 | /* Mode */ |
1583 | if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) { | 1530 | iwe.cmd = SIOCGIWMODE; |
1584 | lbs_deb_scan("i=%d break out: current_ev=%p end_buf=%p " | 1531 | iwe.u.mode = bss->mode; |
1585 | "MAX_SCAN_CELL_SIZE=%zd\n", | 1532 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); |
1586 | i, current_ev, end_buf, MAX_SCAN_CELL_SIZE); | 1533 | |
1587 | break; | 1534 | /* Frequency */ |
1588 | } | 1535 | iwe.cmd = SIOCGIWFREQ; |
1589 | 1536 | iwe.u.freq.m = (long)cfp->freq * 100000; | |
1590 | pscantable = &adapter->scantable[i]; | 1537 | iwe.u.freq.e = 1; |
1591 | 1538 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); | |
1592 | lbs_deb_scan("i %d, ssid '%s'\n", i, pscantable->ssid.ssid); | 1539 | |
1593 | 1540 | /* Add quality statistics */ | |
1594 | cfp = | 1541 | iwe.cmd = IWEVQUAL; |
1595 | libertas_find_cfp_by_band_and_channel(adapter, 0, | 1542 | iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; |
1596 | pscantable->channel); | 1543 | iwe.u.qual.level = SCAN_RSSI(bss->rssi); |
1597 | if (!cfp) { | 1544 | |
1598 | lbs_deb_scan("Invalid channel number %d\n", | 1545 | rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; |
1599 | pscantable->channel); | 1546 | iwe.u.qual.qual = |
1600 | continue; | 1547 | (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * |
1601 | } | 1548 | (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / |
1602 | 1549 | (RSSI_DIFF * RSSI_DIFF); | |
1603 | if (!ssid_valid(&adapter->scantable[i].ssid)) { | 1550 | if (iwe.u.qual.qual > 100) |
1604 | continue; | 1551 | iwe.u.qual.qual = 100; |
1552 | |||
1553 | if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { | ||
1554 | iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
1555 | } else { | ||
1556 | iwe.u.qual.noise = | ||
1557 | CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
1558 | } | ||
1559 | if ((adapter->mode == IW_MODE_AUTO) && | ||
1560 | !libertas_SSID_cmp(&adapter->curbssparams.ssid, &bss->ssid) | ||
1561 | && adapter->adhoccreate) { | ||
1562 | ret = libertas_prepare_and_send_command(priv, | ||
1563 | cmd_802_11_rssi, | ||
1564 | 0, | ||
1565 | cmd_option_waitforrsp, | ||
1566 | 0, NULL); | ||
1567 | |||
1568 | if (!ret) { | ||
1569 | iwe.u.qual.level = | ||
1570 | CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / | ||
1571 | AVG_SCALE, | ||
1572 | adapter->NF[TYPE_RXPD][TYPE_AVG] / | ||
1573 | AVG_SCALE); | ||
1605 | } | 1574 | } |
1575 | } | ||
1576 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); | ||
1606 | 1577 | ||
1607 | /* First entry *MUST* be the AP MAC address */ | 1578 | /* Add encryption capability */ |
1608 | iwe.cmd = SIOCGIWAP; | 1579 | iwe.cmd = SIOCGIWENCODE; |
1609 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 1580 | if (bss->privacy) { |
1610 | memcpy(iwe.u.ap_addr.sa_data, | 1581 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; |
1611 | &adapter->scantable[i].bssid, ETH_ALEN); | 1582 | } else { |
1583 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1584 | } | ||
1585 | iwe.u.data.length = 0; | ||
1586 | start = iwe_stream_add_point(start, stop, &iwe, bss->ssid.ssid); | ||
1612 | 1587 | ||
1613 | iwe.len = IW_EV_ADDR_LEN; | 1588 | current_val = start + IW_EV_LCP_LEN; |
1614 | current_ev = | ||
1615 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1616 | 1589 | ||
1617 | //Add the ESSID | 1590 | iwe.cmd = SIOCGIWRATE; |
1618 | iwe.u.data.length = adapter->scantable[i].ssid.ssidlength; | 1591 | iwe.u.bitrate.fixed = 0; |
1592 | iwe.u.bitrate.disabled = 0; | ||
1593 | iwe.u.bitrate.value = 0; | ||
1619 | 1594 | ||
1620 | if (iwe.u.data.length > 32) { | 1595 | for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) { |
1621 | iwe.u.data.length = 32; | 1596 | u8 rate = bss->libertas_supported_rates[j]; |
1622 | } | 1597 | if (rate == 0) |
1598 | break; /* no more rates */ | ||
1599 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
1600 | iwe.u.bitrate.value = (rate & 0x7f) * 500000; | ||
1601 | current_val = iwe_stream_add_value(start, current_val, | ||
1602 | stop, &iwe, IW_EV_PARAM_LEN); | ||
1603 | } | ||
1604 | if ((bss->mode == IW_MODE_ADHOC) | ||
1605 | && !libertas_SSID_cmp(&adapter->curbssparams.ssid, &bss->ssid) | ||
1606 | && adapter->adhoccreate) { | ||
1607 | iwe.u.bitrate.value = 22 * 500000; | ||
1608 | current_val = iwe_stream_add_value(start, current_val, | ||
1609 | stop, &iwe, IW_EV_PARAM_LEN); | ||
1610 | } | ||
1611 | /* Check if we added any event */ | ||
1612 | if((current_val - start) > IW_EV_LCP_LEN) | ||
1613 | start = current_val; | ||
1614 | |||
1615 | memset(&iwe, 0, sizeof(iwe)); | ||
1616 | if (bss->wpa_ie_len) { | ||
1617 | char buf[MAX_WPA_IE_LEN]; | ||
1618 | memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); | ||
1619 | iwe.cmd = IWEVGENIE; | ||
1620 | iwe.u.data.length = bss->wpa_ie_len; | ||
1621 | start = iwe_stream_add_point(start, stop, &iwe, buf); | ||
1622 | } | ||
1623 | 1623 | ||
1624 | iwe.cmd = SIOCGIWESSID; | 1624 | memset(&iwe, 0, sizeof(iwe)); |
1625 | iwe.u.data.flags = 1; | 1625 | if (bss->rsn_ie_len) { |
1626 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | 1626 | char buf[MAX_WPA_IE_LEN]; |
1627 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 1627 | memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); |
1628 | adapter->scantable[i].ssid. | 1628 | iwe.cmd = IWEVGENIE; |
1629 | ssid); | 1629 | iwe.u.data.length = bss->rsn_ie_len; |
1630 | 1630 | start = iwe_stream_add_point(start, stop, &iwe, buf); | |
1631 | //Add mode | 1631 | } |
1632 | iwe.cmd = SIOCGIWMODE; | ||
1633 | iwe.u.mode = adapter->scantable[i].mode; | ||
1634 | iwe.len = IW_EV_UINT_LEN; | ||
1635 | current_ev = | ||
1636 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1637 | |||
1638 | //frequency | ||
1639 | iwe.cmd = SIOCGIWFREQ; | ||
1640 | iwe.u.freq.m = (long)cfp->freq * 100000; | ||
1641 | iwe.u.freq.e = 1; | ||
1642 | iwe.len = IW_EV_FREQ_LEN; | ||
1643 | current_ev = | ||
1644 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1645 | |||
1646 | /* Add quality statistics */ | ||
1647 | iwe.cmd = IWEVQUAL; | ||
1648 | iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; | ||
1649 | iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi); | ||
1650 | |||
1651 | rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
1652 | iwe.u.qual.qual = | ||
1653 | (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * | ||
1654 | (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / | ||
1655 | (RSSI_DIFF * RSSI_DIFF); | ||
1656 | if (iwe.u.qual.qual > 100) | ||
1657 | iwe.u.qual.qual = 100; | ||
1658 | else if (iwe.u.qual.qual < 1) | ||
1659 | iwe.u.qual.qual = 0; | ||
1660 | |||
1661 | if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { | ||
1662 | iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
1663 | } else { | ||
1664 | iwe.u.qual.noise = | ||
1665 | CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
1666 | } | ||
1667 | if ((adapter->mode == IW_MODE_ADHOC) && | ||
1668 | !libertas_SSID_cmp(&adapter->curbssparams.ssid, | ||
1669 | &adapter->scantable[i].ssid) | ||
1670 | && adapter->adhoccreate) { | ||
1671 | ret = libertas_prepare_and_send_command(priv, | ||
1672 | cmd_802_11_rssi, | ||
1673 | 0, | ||
1674 | cmd_option_waitforrsp, | ||
1675 | 0, NULL); | ||
1676 | |||
1677 | if (!ret) { | ||
1678 | iwe.u.qual.level = | ||
1679 | CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / | ||
1680 | AVG_SCALE, | ||
1681 | adapter->NF[TYPE_RXPD][TYPE_AVG] / | ||
1682 | AVG_SCALE); | ||
1683 | } | ||
1684 | } | ||
1685 | iwe.len = IW_EV_QUAL_LEN; | ||
1686 | current_ev = | ||
1687 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1688 | |||
1689 | /* Add encryption capability */ | ||
1690 | iwe.cmd = SIOCGIWENCODE; | ||
1691 | if (adapter->scantable[i].privacy) { | ||
1692 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1693 | } else { | ||
1694 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1695 | } | ||
1696 | iwe.u.data.length = 0; | ||
1697 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1698 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1699 | adapter->scantable->ssid. | ||
1700 | ssid); | ||
1701 | 1632 | ||
1702 | current_val = current_ev + IW_EV_LCP_LEN; | 1633 | return start; |
1634 | } | ||
1703 | 1635 | ||
1704 | iwe.cmd = SIOCGIWRATE; | 1636 | /** |
1637 | * @brief Retrieve the scan table entries via wireless tools IOCTL call | ||
1638 | * | ||
1639 | * @param dev A pointer to net_device structure | ||
1640 | * @param info A pointer to iw_request_info structure | ||
1641 | * @param dwrq A pointer to iw_point structure | ||
1642 | * @param extra A pointer to extra data buf | ||
1643 | * | ||
1644 | * @return 0 --success, otherwise fail | ||
1645 | */ | ||
1646 | int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, | ||
1647 | struct iw_point *dwrq, char *extra) | ||
1648 | { | ||
1649 | #define SCAN_ITEM_SIZE 128 | ||
1650 | wlan_private *priv = dev->priv; | ||
1651 | wlan_adapter *adapter = priv->adapter; | ||
1652 | int err = 0; | ||
1653 | char *ev = extra; | ||
1654 | char *stop = ev + dwrq->length; | ||
1655 | struct bss_descriptor * iter_bss; | ||
1656 | struct bss_descriptor * safe; | ||
1705 | 1657 | ||
1706 | iwe.u.bitrate.fixed = 0; | 1658 | lbs_deb_enter(LBS_DEB_ASSOC); |
1707 | iwe.u.bitrate.disabled = 0; | ||
1708 | iwe.u.bitrate.value = 0; | ||
1709 | 1659 | ||
1710 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | 1660 | /* If we've got an uncompleted scan, schedule the next part */ |
1711 | for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates); | 1661 | if (!adapter->nr_cmd_pending && adapter->last_scanned_channel) |
1712 | j++) { | 1662 | wlan_scan_networks(priv, NULL, 0); |
1713 | if (adapter->scantable[i].libertas_supported_rates[j] == 0) { | ||
1714 | break; | ||
1715 | } | ||
1716 | rate = | ||
1717 | (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) * | ||
1718 | 500000; | ||
1719 | if (rate > iwe.u.bitrate.value) { | ||
1720 | iwe.u.bitrate.value = rate; | ||
1721 | } | ||
1722 | 1663 | ||
1723 | iwe.u.bitrate.value = | 1664 | mutex_lock(&adapter->lock); |
1724 | (adapter->scantable[i].libertas_supported_rates[j] | 1665 | list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { |
1725 | & 0x7f) * 500000; | 1666 | char * next_ev; |
1726 | iwe.len = IW_EV_PARAM_LEN; | 1667 | unsigned long stale_time; |
1727 | current_ev = | ||
1728 | iwe_stream_add_value(current_ev, current_val, | ||
1729 | end_buf, &iwe, iwe.len); | ||
1730 | 1668 | ||
1669 | if (stop - ev < SCAN_ITEM_SIZE) { | ||
1670 | err = -E2BIG; | ||
1671 | break; | ||
1731 | } | 1672 | } |
1732 | if ((adapter->scantable[i].mode == IW_MODE_ADHOC) | ||
1733 | && !libertas_SSID_cmp(&adapter->curbssparams.ssid, | ||
1734 | &adapter->scantable[i].ssid) | ||
1735 | && adapter->adhoccreate) { | ||
1736 | iwe.u.bitrate.value = 22 * 500000; | ||
1737 | } | ||
1738 | iwe.len = IW_EV_PARAM_LEN; | ||
1739 | current_ev = | ||
1740 | iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, | ||
1741 | iwe.len); | ||
1742 | |||
1743 | /* Add new value to event */ | ||
1744 | current_val = current_ev + IW_EV_LCP_LEN; | ||
1745 | |||
1746 | if (adapter->scantable[i].rsn_ie[0] == WPA2_IE) { | ||
1747 | memset(&iwe, 0, sizeof(iwe)); | ||
1748 | memset(buf, 0, sizeof(buf)); | ||
1749 | memcpy(buf, adapter->scantable[i].rsn_ie, | ||
1750 | adapter->scantable[i].rsn_ie_len); | ||
1751 | iwe.cmd = IWEVGENIE; | ||
1752 | iwe.u.data.length = adapter->scantable[i].rsn_ie_len; | ||
1753 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1754 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
1755 | &iwe, buf); | ||
1756 | } | ||
1757 | if (adapter->scantable[i].wpa_ie[0] == WPA_IE) { | ||
1758 | memset(&iwe, 0, sizeof(iwe)); | ||
1759 | memset(buf, 0, sizeof(buf)); | ||
1760 | memcpy(buf, adapter->scantable[i].wpa_ie, | ||
1761 | adapter->scantable[i].wpa_ie_len); | ||
1762 | iwe.cmd = IWEVGENIE; | ||
1763 | iwe.u.data.length = adapter->scantable[i].wpa_ie_len; | ||
1764 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1765 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
1766 | &iwe, buf); | ||
1767 | } | ||
1768 | |||
1769 | |||
1770 | if (adapter->scantable[i].extra_ie != 0) { | ||
1771 | memset(&iwe, 0, sizeof(iwe)); | ||
1772 | memset(buf, 0, sizeof(buf)); | ||
1773 | ptr = buf; | ||
1774 | ptr += sprintf(ptr, "extra_ie"); | ||
1775 | iwe.u.data.length = strlen(buf); | ||
1776 | 1673 | ||
1777 | lbs_deb_scan("iwe.u.data.length %d\n", | 1674 | /* Prune old an old scan result */ |
1778 | iwe.u.data.length); | 1675 | stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; |
1779 | lbs_deb_scan("BUF: %s \n", buf); | 1676 | if (time_after(jiffies, stale_time)) { |
1780 | 1677 | list_move_tail (&iter_bss->list, | |
1781 | iwe.cmd = IWEVCUSTOM; | 1678 | &adapter->network_free_list); |
1782 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | 1679 | clear_bss_descriptor(iter_bss); |
1783 | current_ev = | 1680 | continue; |
1784 | iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1785 | buf); | ||
1786 | } | 1681 | } |
1787 | 1682 | ||
1788 | current_val = current_ev + IW_EV_LCP_LEN; | 1683 | /* Translate to WE format this entry */ |
1789 | 1684 | next_ev = libertas_translate_scan(priv, ev, stop, iter_bss); | |
1790 | /* | 1685 | if (next_ev == NULL) |
1791 | * Check if we added any event | 1686 | continue; |
1792 | */ | 1687 | ev = next_ev; |
1793 | if ((current_val - current_ev) > IW_EV_LCP_LEN) | ||
1794 | current_ev = current_val; | ||
1795 | } | 1688 | } |
1689 | mutex_unlock(&adapter->lock); | ||
1796 | 1690 | ||
1797 | dwrq->length = (current_ev - extra); | 1691 | dwrq->length = (ev - extra); |
1798 | dwrq->flags = 0; | 1692 | dwrq->flags = 0; |
1799 | 1693 | ||
1800 | lbs_deb_leave(LBS_DEB_ASSOC); | 1694 | lbs_deb_leave(LBS_DEB_ASSOC); |
1801 | return 0; | 1695 | return err; |
1802 | } | 1696 | } |
1803 | 1697 | ||
1804 | /** | 1698 | /** |
@@ -1850,6 +1744,18 @@ int libertas_cmd_80211_scan(wlan_private * priv, | |||
1850 | return 0; | 1744 | return 0; |
1851 | } | 1745 | } |
1852 | 1746 | ||
1747 | static inline int is_same_network(struct bss_descriptor *src, | ||
1748 | struct bss_descriptor *dst) | ||
1749 | { | ||
1750 | /* A network is only a duplicate if the channel, BSSID, and ESSID | ||
1751 | * all match. We treat all <hidden> with the same BSSID and channel | ||
1752 | * as one network */ | ||
1753 | return ((src->ssid.ssidlength == dst->ssid.ssidlength) && | ||
1754 | (src->channel == dst->channel) && | ||
1755 | !compare_ether_addr(src->bssid, dst->bssid) && | ||
1756 | !memcmp(src->ssid.ssid, dst->ssid.ssid, src->ssid.ssidlength)); | ||
1757 | } | ||
1758 | |||
1853 | /** | 1759 | /** |
1854 | * @brief This function handles the command response of scan | 1760 | * @brief This function handles the command response of scan |
1855 | * | 1761 | * |
@@ -1878,14 +1784,13 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) | |||
1878 | { | 1784 | { |
1879 | wlan_adapter *adapter = priv->adapter; | 1785 | wlan_adapter *adapter = priv->adapter; |
1880 | struct cmd_ds_802_11_scan_rsp *pscan; | 1786 | struct cmd_ds_802_11_scan_rsp *pscan; |
1881 | struct bss_descriptor newbssentry; | ||
1882 | struct mrvlietypes_data *ptlv; | 1787 | struct mrvlietypes_data *ptlv; |
1883 | struct mrvlietypes_tsftimestamp *ptsftlv; | 1788 | struct mrvlietypes_tsftimestamp *ptsftlv; |
1789 | struct bss_descriptor * iter_bss; | ||
1790 | struct bss_descriptor * safe; | ||
1884 | u8 *pbssinfo; | 1791 | u8 *pbssinfo; |
1885 | u16 scanrespsize; | 1792 | u16 scanrespsize; |
1886 | int bytesleft; | 1793 | int bytesleft; |
1887 | int numintable; | ||
1888 | int bssIdx; | ||
1889 | int idx; | 1794 | int idx; |
1890 | int tlvbufsize; | 1795 | int tlvbufsize; |
1891 | u64 tsfval; | 1796 | u64 tsfval; |
@@ -1893,12 +1798,21 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) | |||
1893 | 1798 | ||
1894 | lbs_deb_enter(LBS_DEB_ASSOC); | 1799 | lbs_deb_enter(LBS_DEB_ASSOC); |
1895 | 1800 | ||
1801 | /* Prune old entries from scan table */ | ||
1802 | list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { | ||
1803 | unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; | ||
1804 | if (time_before(jiffies, stale_time)) | ||
1805 | continue; | ||
1806 | list_move_tail (&iter_bss->list, &adapter->network_free_list); | ||
1807 | clear_bss_descriptor(iter_bss); | ||
1808 | } | ||
1809 | |||
1896 | pscan = &resp->params.scanresp; | 1810 | pscan = &resp->params.scanresp; |
1897 | 1811 | ||
1898 | if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) { | 1812 | if (pscan->nr_sets > MAX_NETWORK_COUNT) { |
1899 | lbs_deb_scan( | 1813 | lbs_deb_scan( |
1900 | "SCAN_RESP: Invalid number of AP returned (%d)!!\n", | 1814 | "SCAN_RESP: too many scan results (%d, max %d)!!\n", |
1901 | pscan->nr_sets); | 1815 | pscan->nr_sets, MAX_NETWORK_COUNT); |
1902 | ret = -1; | 1816 | ret = -1; |
1903 | goto done; | 1817 | goto done; |
1904 | } | 1818 | } |
@@ -1910,7 +1824,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) | |||
1910 | lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n", | 1824 | lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n", |
1911 | pscan->nr_sets); | 1825 | pscan->nr_sets); |
1912 | 1826 | ||
1913 | numintable = adapter->numinscantable; | ||
1914 | pbssinfo = pscan->bssdesc_and_tlvbuffer; | 1827 | pbssinfo = pscan->bssdesc_and_tlvbuffer; |
1915 | 1828 | ||
1916 | /* The size of the TLV buffer is equal to the entire command response | 1829 | /* The size of the TLV buffer is equal to the entire command response |
@@ -1934,102 +1847,68 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) | |||
1934 | * or as an addition at the end of the table | 1847 | * or as an addition at the end of the table |
1935 | */ | 1848 | */ |
1936 | for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { | 1849 | for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { |
1937 | /* Zero out the newbssentry we are about to store info in */ | 1850 | struct bss_descriptor new; |
1938 | memset(&newbssentry, 0x00, sizeof(newbssentry)); | 1851 | struct bss_descriptor * found = NULL; |
1852 | struct bss_descriptor * iter_bss = NULL; | ||
1853 | struct bss_descriptor * oldest = NULL; | ||
1939 | 1854 | ||
1940 | /* Process the data fields and IEs returned for this BSS */ | 1855 | /* Process the data fields and IEs returned for this BSS */ |
1941 | if ((InterpretBSSDescriptionWithIE(&newbssentry, | 1856 | memset(&new, 0, sizeof (struct bss_descriptor)); |
1942 | &pbssinfo, | 1857 | if (libertas_process_bss(&new, &pbssinfo, &bytesleft) != 0) { |
1943 | &bytesleft) == | 1858 | /* error parsing the scan response, skipped */ |
1944 | 0) | 1859 | lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); |
1945 | && CHECK_SSID_IS_VALID(&newbssentry.ssid)) { | 1860 | continue; |
1946 | 1861 | } | |
1947 | lbs_deb_scan( | ||
1948 | "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1949 | newbssentry.bssid[0], | ||
1950 | newbssentry.bssid[1], | ||
1951 | newbssentry.bssid[2], | ||
1952 | newbssentry.bssid[3], | ||
1953 | newbssentry.bssid[4], | ||
1954 | newbssentry.bssid[5]); | ||
1955 | |||
1956 | /* | ||
1957 | * Search the scan table for the same bssid | ||
1958 | */ | ||
1959 | for (bssIdx = 0; bssIdx < numintable; bssIdx++) { | ||
1960 | if (memcmp(newbssentry.bssid, | ||
1961 | adapter->scantable[bssIdx].bssid, | ||
1962 | sizeof(newbssentry.bssid)) == 0) { | ||
1963 | /* | ||
1964 | * If the SSID matches as well, it is a duplicate of | ||
1965 | * this entry. Keep the bssIdx set to this | ||
1966 | * entry so we replace the old contents in the table | ||
1967 | */ | ||
1968 | if ((newbssentry.ssid.ssidlength == | ||
1969 | adapter->scantable[bssIdx].ssid. | ||
1970 | ssidlength) | ||
1971 | && | ||
1972 | (memcmp | ||
1973 | (newbssentry.ssid.ssid, | ||
1974 | adapter->scantable[bssIdx].ssid. | ||
1975 | ssid, | ||
1976 | newbssentry.ssid.ssidlength) == | ||
1977 | 0)) { | ||
1978 | lbs_deb_scan( | ||
1979 | "SCAN_RESP: Duplicate of index: %d\n", | ||
1980 | bssIdx); | ||
1981 | break; | ||
1982 | } | ||
1983 | } | ||
1984 | } | ||
1985 | /* | ||
1986 | * If the bssIdx is equal to the number of entries in the table, | ||
1987 | * the new entry was not a duplicate; append it to the scan | ||
1988 | * table | ||
1989 | */ | ||
1990 | if (bssIdx == numintable) { | ||
1991 | /* Range check the bssIdx, keep it limited to the last entry */ | ||
1992 | if (bssIdx == MRVDRV_MAX_BSSID_LIST) { | ||
1993 | bssIdx--; | ||
1994 | } else { | ||
1995 | numintable++; | ||
1996 | } | ||
1997 | } | ||
1998 | |||
1999 | /* | ||
2000 | * If the TSF TLV was appended to the scan results, save the | ||
2001 | * this entries TSF value in the networktsf field. The | ||
2002 | * networktsf is the firmware's TSF value at the time the | ||
2003 | * beacon or probe response was received. | ||
2004 | */ | ||
2005 | if (ptsftlv) { | ||
2006 | memcpy(&tsfval, &ptsftlv->tsftable[idx], | ||
2007 | sizeof(tsfval)); | ||
2008 | tsfval = le64_to_cpu(tsfval); | ||
2009 | 1862 | ||
2010 | memcpy(&newbssentry.networktsf, | 1863 | /* Try to find this bss in the scan table */ |
2011 | &tsfval, sizeof(newbssentry.networktsf)); | 1864 | list_for_each_entry (iter_bss, &adapter->network_list, list) { |
1865 | if (is_same_network(iter_bss, &new)) { | ||
1866 | found = iter_bss; | ||
1867 | break; | ||
2012 | } | 1868 | } |
2013 | 1869 | ||
2014 | /* Copy the locally created newbssentry to the scan table */ | 1870 | if ((oldest == NULL) || |
2015 | memcpy(&adapter->scantable[bssIdx], | 1871 | (iter_bss->last_scanned < oldest->last_scanned)) |
2016 | &newbssentry, | 1872 | oldest = iter_bss; |
2017 | sizeof(adapter->scantable[bssIdx])); | 1873 | } |
2018 | 1874 | ||
1875 | if (found) { | ||
1876 | /* found, clear it */ | ||
1877 | clear_bss_descriptor(found); | ||
1878 | } else if (!list_empty(&adapter->network_free_list)) { | ||
1879 | /* Pull one from the free list */ | ||
1880 | found = list_entry(adapter->network_free_list.next, | ||
1881 | struct bss_descriptor, list); | ||
1882 | list_move_tail(&found->list, &adapter->network_list); | ||
1883 | } else if (oldest) { | ||
1884 | /* If there are no more slots, expire the oldest */ | ||
1885 | found = oldest; | ||
1886 | clear_bss_descriptor(found); | ||
1887 | list_move_tail(&found->list, &adapter->network_list); | ||
2019 | } else { | 1888 | } else { |
1889 | continue; | ||
1890 | } | ||
2020 | 1891 | ||
2021 | /* error parsing/interpreting the scan response, skipped */ | 1892 | lbs_deb_scan("SCAN_RESP: BSSID = " MAC_FMT "\n", |
2022 | lbs_deb_scan("SCAN_RESP: " | 1893 | new.bssid[0], new.bssid[1], new.bssid[2], |
2023 | "InterpretBSSDescriptionWithIE returned ERROR\n"); | 1894 | new.bssid[3], new.bssid[4], new.bssid[5]); |
1895 | |||
1896 | /* | ||
1897 | * If the TSF TLV was appended to the scan results, save the | ||
1898 | * this entries TSF value in the networktsf field. The | ||
1899 | * networktsf is the firmware's TSF value at the time the | ||
1900 | * beacon or probe response was received. | ||
1901 | */ | ||
1902 | if (ptsftlv) { | ||
1903 | memcpy(&tsfval, &ptsftlv->tsftable[idx], sizeof(tsfval)); | ||
1904 | tsfval = le64_to_cpu(tsfval); | ||
1905 | memcpy(&new.networktsf, &tsfval, sizeof(new.networktsf)); | ||
2024 | } | 1906 | } |
2025 | } | ||
2026 | 1907 | ||
2027 | lbs_deb_scan("SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", | 1908 | /* Copy the locally created newbssentry to the scan table */ |
2028 | pscan->nr_sets, numintable - adapter->numinscantable, | 1909 | memcpy(found, &new, offsetof(struct bss_descriptor, list)); |
2029 | numintable); | 1910 | } |
2030 | 1911 | ||
2031 | /* Update the total number of BSSIDs in the scan table */ | ||
2032 | adapter->numinscantable = numintable; | ||
2033 | ret = 0; | 1912 | ret = 0; |
2034 | 1913 | ||
2035 | done: | 1914 | done: |