[PATCH] libertas: remove WPA_SUPPLICANT structure
[safe/jmp/linux-2.6] / drivers / net / wireless / libertas / scan.c
1 /* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
2 /* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
3
4 /**
5   * Functions implementing wlan scan IOCTL and firmware command APIs
6   *
7   * IOCTL handlers as well as command preperation and response routines
8   *  for sending scan commands to the firmware.
9   */
10 #include <linux/ctype.h>
11 #include <linux/if.h>
12 #include <linux/netdevice.h>
13 #include <linux/wireless.h>
14
15 #include <net/ieee80211.h>
16 #include <net/iw_handler.h>
17
18 #include "host.h"
19 #include "decl.h"
20 #include "dev.h"
21 #include "scan.h"
22
23 //! Approximate amount of data needed to pass a scan result back to iwlist
24 #define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
25                              + IW_ESSID_MAX_SIZE        \
26                              + IW_EV_UINT_LEN           \
27                              + IW_EV_FREQ_LEN           \
28                              + IW_EV_QUAL_LEN           \
29                              + IW_ESSID_MAX_SIZE        \
30                              + IW_EV_PARAM_LEN          \
31                              + 40)      /* 40 for WPAIE */
32
33 //! Memory needed to store a max sized channel List TLV for a firmware scan
34 #define CHAN_TLV_MAX_SIZE  (sizeof(struct mrvlietypesheader)    \
35                             + (MRVDRV_MAX_CHANNELS_PER_SCAN     \
36                                * sizeof(struct chanscanparamset)))
37
38 //! Memory needed to store a max number/size SSID TLV for a firmware scan
39 #define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvlietypes_ssidparamset))
40
41 //! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
42 #define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config)  \
43                             + sizeof(struct mrvlietypes_numprobes)   \
44                             + CHAN_TLV_MAX_SIZE                 \
45                             + SSID_TLV_MAX_SIZE)
46
47 //! The maximum number of channels the firmware can scan per command
48 #define MRVDRV_MAX_CHANNELS_PER_SCAN   14
49
50 /**
51  * @brief Number of channels to scan per firmware scan command issuance.
52  *
53  *  Number restricted to prevent hitting the limit on the amount of scan data
54  *  returned in a single firmware scan command.
55  */
56 #define MRVDRV_CHANNELS_PER_SCAN_CMD   4
57
58 //! Scan time specified in the channel TLV for each channel for passive scans
59 #define MRVDRV_PASSIVE_SCAN_CHAN_TIME  100
60
61 //! Scan time specified in the channel TLV for each channel for active scans
62 #define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
63
64 //! Macro to enable/disable SSID checking before storing a scan table
65 #ifdef DISCARD_BAD_SSID
66 #define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid)
67 #else
68 #define CHECK_SSID_IS_VALID(x) 1
69 #endif
70
71 /**
72  *  @brief Check if a scanned network compatible with the driver settings
73  *
74  *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
75  * enabled enabled  enabled   AES     mode   privacy  WPA  WPA2  Compatible
76  *    0       0        0       0      NONE      0      0    0   yes No security
77  *    1       0        0       0      NONE      1      0    0   yes Static WEP
78  *    0       1        0       0       x        1x     1    x   yes WPA
79  *    0       0        1       0       x        1x     x    1   yes WPA2
80  *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
81  *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
82  *
83  *
84  *  @param adapter A pointer to wlan_adapter
85  *  @param index   Index in scantable to check against current driver settings
86  *  @param mode    Network mode: Infrastructure or IBSS
87  *
88  *  @return        Index in scantable, or error code if negative
89  */
90 static int is_network_compatible(wlan_adapter * adapter, int index, int mode)
91 {
92         ENTER();
93
94         if (adapter->scantable[index].inframode == mode) {
95                 if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
96                     && !adapter->secinfo.WPAenabled
97                     && !adapter->secinfo.WPA2enabled
98                     && adapter->scantable[index].wpa_ie[0] != WPA_IE
99                     && adapter->scantable[index].rsn_ie[0] != WPA2_IE
100                     && adapter->secinfo.Encryptionmode == CIPHER_NONE
101                     && !adapter->scantable[index].privacy) {
102                         /* no security */
103                         LEAVE();
104                         return index;
105                 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled
106                            && !adapter->secinfo.WPAenabled
107                            && !adapter->secinfo.WPA2enabled
108                            && adapter->scantable[index].privacy) {
109                         /* static WEP enabled */
110                         LEAVE();
111                         return index;
112                 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
113                            && adapter->secinfo.WPAenabled
114                            && !adapter->secinfo.WPA2enabled
115                            && (adapter->scantable[index].wpa_ie[0] == WPA_IE)
116                            /* privacy bit may NOT be set in some APs like LinkSys WRT54G
117                               && adapter->scantable[index].privacy */
118                     ) {
119                         /* WPA enabled */
120                         lbs_pr_debug(1,
121                                "is_network_compatible() WPA: index=%d wpa_ie=%#x "
122                                "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
123                                "privacy=%#x\n", index,
124                                adapter->scantable[index].wpa_ie[0],
125                                adapter->scantable[index].rsn_ie[0],
126                                (adapter->secinfo.WEPstatus ==
127                                 wlan802_11WEPenabled) ? "e" : "d",
128                                (adapter->secinfo.WPAenabled) ? "e" : "d",
129                                (adapter->secinfo.WPA2enabled) ? "e" : "d",
130                                adapter->secinfo.Encryptionmode,
131                                adapter->scantable[index].privacy);
132                         LEAVE();
133                         return index;
134                 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
135                            && !adapter->secinfo.WPAenabled
136                            && adapter->secinfo.WPA2enabled
137                            && (adapter->scantable[index].rsn_ie[0] == WPA2_IE)
138                            /* privacy bit may NOT be set in some APs like LinkSys WRT54G
139                               && adapter->scantable[index].privacy */
140                     ) {
141                         /* WPA2 enabled */
142                         lbs_pr_debug(1,
143                                "is_network_compatible() WPA2: index=%d wpa_ie=%#x "
144                                "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
145                                "privacy=%#x\n", index,
146                                adapter->scantable[index].wpa_ie[0],
147                                adapter->scantable[index].rsn_ie[0],
148                                (adapter->secinfo.WEPstatus ==
149                                 wlan802_11WEPenabled) ? "e" : "d",
150                                (adapter->secinfo.WPAenabled) ? "e" : "d",
151                                (adapter->secinfo.WPA2enabled) ? "e" : "d",
152                                adapter->secinfo.Encryptionmode,
153                                adapter->scantable[index].privacy);
154                         LEAVE();
155                         return index;
156                 } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
157                            && !adapter->secinfo.WPAenabled
158                            && !adapter->secinfo.WPA2enabled
159                            && (adapter->scantable[index].wpa_ie[0] != WPA_IE)
160                            && (adapter->scantable[index].rsn_ie[0] != WPA2_IE)
161                            && adapter->secinfo.Encryptionmode != CIPHER_NONE
162                            && adapter->scantable[index].privacy) {
163                         /* dynamic WEP enabled */
164                         lbs_pr_debug(1,
165                                "is_network_compatible() dynamic WEP: index=%d "
166                                "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n",
167                                index,
168                                adapter->scantable[index].wpa_ie[0],
169                                adapter->scantable[index].rsn_ie[0],
170                                adapter->secinfo.Encryptionmode,
171                                adapter->scantable[index].privacy);
172                         LEAVE();
173                         return index;
174                 }
175
176                 /* security doesn't match */
177                 lbs_pr_debug(1,
178                        "is_network_compatible() FAILED: index=%d wpa_ie=%#x "
179                        "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n",
180                        index,
181                        adapter->scantable[index].wpa_ie[0],
182                        adapter->scantable[index].rsn_ie[0],
183                        (adapter->secinfo.WEPstatus ==
184                         wlan802_11WEPenabled) ? "e" : "d",
185                        (adapter->secinfo.WPAenabled) ? "e" : "d",
186                        (adapter->secinfo.WPA2enabled) ? "e" : "d",
187                        adapter->secinfo.Encryptionmode,
188                        adapter->scantable[index].privacy);
189                 LEAVE();
190                 return -ECONNREFUSED;
191         }
192
193         /* mode doesn't match */
194         LEAVE();
195         return -ENETUNREACH;
196 }
197
198 /**
199  *  @brief This function validates a SSID as being able to be printed
200  *
201  *  @param pssid   SSID structure to validate
202  *
203  *  @return        TRUE or FALSE
204  */
205 static u8 ssid_valid(struct WLAN_802_11_SSID *pssid)
206 {
207         int ssididx;
208
209         for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) {
210                 if (!isprint(pssid->ssid[ssididx])) {
211                         return 0;
212                 }
213         }
214
215         return 1;
216 }
217
218 /**
219  *  @brief Post process the scan table after a new scan command has completed
220  *
221  *  Inspect each entry of the scan table and try to find an entry that
222  *    matches our current associated/joined network from the scan.  If
223  *    one is found, update the stored copy of the bssdescriptor for our
224  *    current network.
225  *
226  *  Debug dump the current scan table contents if compiled accordingly.
227  *
228  *  @param priv   A pointer to wlan_private structure
229  *
230  *  @return       void
231  */
232 static void wlan_scan_process_results(wlan_private * priv)
233 {
234         wlan_adapter *adapter = priv->adapter;
235         int foundcurrent;
236         int i;
237
238         foundcurrent = 0;
239
240         if (adapter->connect_status == libertas_connected) {
241                 /* try to find the current BSSID in the new scan list */
242                 for (i = 0; i < adapter->numinscantable; i++) {
243                         if (!libertas_SSID_cmp(&adapter->scantable[i].ssid,
244                                      &adapter->curbssparams.ssid) &&
245                             !memcmp(adapter->curbssparams.bssid,
246                                     adapter->scantable[i].macaddress,
247                                     ETH_ALEN)) {
248                                 foundcurrent = 1;
249                         }
250                 }
251
252                 if (foundcurrent) {
253                         /* Make a copy of current BSSID descriptor */
254                         memcpy(&adapter->curbssparams.bssdescriptor,
255                                &adapter->scantable[i],
256                                sizeof(adapter->curbssparams.bssdescriptor));
257                 }
258         }
259
260         for (i = 0; i < adapter->numinscantable; i++) {
261                 lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
262                        "RSSI[%03d], SSID[%s]\n",
263                        i,
264                        adapter->scantable[i].macaddress[0],
265                        adapter->scantable[i].macaddress[1],
266                        adapter->scantable[i].macaddress[2],
267                        adapter->scantable[i].macaddress[3],
268                        adapter->scantable[i].macaddress[4],
269                        adapter->scantable[i].macaddress[5],
270                        (s32) adapter->scantable[i].rssi,
271                        adapter->scantable[i].ssid.ssid);
272         }
273 }
274
275 /**
276  *  @brief Create a channel list for the driver to scan based on region info
277  *
278  *  Use the driver region/band information to construct a comprehensive list
279  *    of channels to scan.  This routine is used for any scan that is not
280  *    provided a specific channel list to scan.
281  *
282  *  @param priv          A pointer to wlan_private structure
283  *  @param scanchanlist  Output parameter: resulting channel list to scan
284  *  @param filteredscan  Flag indicating whether or not a BSSID or SSID filter
285  *                       is being sent in the command to firmware.  Used to
286  *                       increase the number of channels sent in a scan
287  *                       command and to disable the firmware channel scan
288  *                       filter.
289  *
290  *  @return              void
291  */
292 static void wlan_scan_create_channel_list(wlan_private * priv,
293                                           struct chanscanparamset * scanchanlist,
294                                           u8 filteredscan)
295 {
296
297         wlan_adapter *adapter = priv->adapter;
298         struct region_channel *scanregion;
299         struct chan_freq_power *cfp;
300         int rgnidx;
301         int chanidx;
302         int nextchan;
303         u8 scantype;
304
305         chanidx = 0;
306
307         /* Set the default scan type to the user specified type, will later
308          *   be changed to passive on a per channel basis if restricted by
309          *   regulatory requirements (11d or 11h)
310          */
311         scantype = adapter->scantype;
312
313         for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
314                 if (priv->adapter->enable11d &&
315                     adapter->connect_status != libertas_connected) {
316                         /* Scan all the supported chan for the first scan */
317                         if (!adapter->universal_channel[rgnidx].valid)
318                                 continue;
319                         scanregion = &adapter->universal_channel[rgnidx];
320
321                         /* clear the parsed_region_chan for the first scan */
322                         memset(&adapter->parsed_region_chan, 0x00,
323                                sizeof(adapter->parsed_region_chan));
324                 } else {
325                         if (!adapter->region_channel[rgnidx].valid)
326                                 continue;
327                         scanregion = &adapter->region_channel[rgnidx];
328                 }
329
330                 for (nextchan = 0;
331                      nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
332
333                         cfp = scanregion->CFP + nextchan;
334
335                         if (priv->adapter->enable11d) {
336                                 scantype =
337                                     libertas_get_scan_type_11d(cfp->channel,
338                                                            &adapter->
339                                                            parsed_region_chan);
340                         }
341
342                         switch (scanregion->band) {
343                         case BAND_B:
344                         case BAND_G:
345                         default:
346                                 scanchanlist[chanidx].radiotype =
347                                     cmd_scan_radio_type_bg;
348                                 break;
349                         }
350
351                         if (scantype == cmd_scan_type_passive) {
352                                 scanchanlist[chanidx].maxscantime =
353                                     cpu_to_le16
354                                     (MRVDRV_PASSIVE_SCAN_CHAN_TIME);
355                                 scanchanlist[chanidx].chanscanmode.passivescan =
356                                     1;
357                         } else {
358                                 scanchanlist[chanidx].maxscantime =
359                                     cpu_to_le16
360                                     (MRVDRV_ACTIVE_SCAN_CHAN_TIME);
361                                 scanchanlist[chanidx].chanscanmode.passivescan =
362                                     0;
363                         }
364
365                         scanchanlist[chanidx].channumber = cfp->channel;
366
367                         if (filteredscan) {
368                                 scanchanlist[chanidx].chanscanmode.
369                                     disablechanfilt = 1;
370                         }
371                 }
372         }
373 }
374
375 /**
376  *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
377  *
378  *  Application layer or other functions can invoke wlan_scan_networks
379  *    with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
380  *    This structure is used as the basis of one or many wlan_scan_cmd_config
381  *    commands that are sent to the command processing module and sent to
382  *    firmware.
383  *
384  *  Create a wlan_scan_cmd_config based on the following user supplied
385  *    parameters (if present):
386  *             - SSID filter
387  *             - BSSID filter
388  *             - Number of Probes to be sent
389  *             - channel list
390  *
391  *  If the SSID or BSSID filter is not present, disable/clear the filter.
392  *  If the number of probes is not set, use the adapter default setting
393  *  Qualify the channel
394  *
395  *  @param priv             A pointer to wlan_private structure
396  *  @param puserscanin      NULL or pointer to scan configuration parameters
397  *  @param ppchantlvout     Output parameter: Pointer to the start of the
398  *                          channel TLV portion of the output scan config
399  *  @param pscanchanlist    Output parameter: Pointer to the resulting channel
400  *                          list to scan
401  *  @param pmaxchanperscan  Output parameter: Number of channels to scan for
402  *                          each issuance of the firmware scan command
403  *  @param pfilteredscan    Output parameter: Flag indicating whether or not
404  *                          a BSSID or SSID filter is being sent in the
405  *                          command to firmware.  Used to increase the number
406  *                          of channels sent in a scan command and to
407  *                          disable the firmware channel scan filter.
408  *  @param pscancurrentonly Output parameter: Flag indicating whether or not
409  *                          we are only scanning our current active channel
410  *
411  *  @return                 resulting scan configuration
412  */
413 static struct wlan_scan_cmd_config *
414 wlan_scan_setup_scan_config(wlan_private * priv,
415                             const struct wlan_ioctl_user_scan_cfg * puserscanin,
416                             struct mrvlietypes_chanlistparamset ** ppchantlvout,
417                             struct chanscanparamset * pscanchanlist,
418                             int *pmaxchanperscan,
419                             u8 * pfilteredscan,
420                             u8 * pscancurrentonly)
421 {
422         wlan_adapter *adapter = priv->adapter;
423         const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
424         struct mrvlietypes_numprobes *pnumprobestlv;
425         struct mrvlietypes_ssidparamset *pssidtlv;
426         struct wlan_scan_cmd_config * pscancfgout = NULL;
427         u8 *ptlvpos;
428         u16 numprobes;
429         u16 ssidlen;
430         int chanidx;
431         int scantype;
432         int scandur;
433         int channel;
434         int radiotype;
435
436         pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
437         if (pscancfgout == NULL)
438                 goto out;
439
440         /* The tlvbufferlen is calculated for each scan command.  The TLVs added
441          *   in this routine will be preserved since the routine that sends
442          *   the command will append channelTLVs at *ppchantlvout.  The difference
443          *   between the *ppchantlvout and the tlvbuffer start will be used
444          *   to calculate the size of anything we add in this routine.
445          */
446         pscancfgout->tlvbufferlen = 0;
447
448         /* Running tlv pointer.  Assigned to ppchantlvout at end of function
449          *  so later routines know where channels can be added to the command buf
450          */
451         ptlvpos = pscancfgout->tlvbuffer;
452
453         /*
454          * Set the initial scan paramters for progressive scanning.  If a specific
455          *   BSSID or SSID is used, the number of channels in the scan command
456          *   will be increased to the absolute maximum
457          */
458         *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
459
460         /* Initialize the scan as un-filtered by firmware, set to TRUE below if
461          *   a SSID or BSSID filter is sent in the command
462          */
463         *pfilteredscan = 0;
464
465         /* Initialize the scan as not being only on the current channel.  If
466          *   the channel list is customized, only contains one channel, and
467          *   is the active channel, this is set true and data flow is not halted.
468          */
469         *pscancurrentonly = 0;
470
471         if (puserscanin) {
472
473                 /* Set the bss type scan filter, use adapter setting if unset */
474                 pscancfgout->bsstype =
475                     (puserscanin->bsstype ? puserscanin->bsstype : adapter->
476                      scanmode);
477
478                 /* Set the number of probes to send, use adapter setting if unset */
479                 numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
480                              adapter->scanprobes);
481
482                 /*
483                  * Set the BSSID filter to the incoming configuration,
484                  *   if non-zero.  If not set, it will remain disabled (all zeros).
485                  */
486                 memcpy(pscancfgout->specificBSSID,
487                        puserscanin->specificBSSID,
488                        sizeof(pscancfgout->specificBSSID));
489
490                 ssidlen = strlen(puserscanin->specificSSID);
491
492                 if (ssidlen) {
493                         pssidtlv =
494                             (struct mrvlietypes_ssidparamset *) pscancfgout->
495                             tlvbuffer;
496                         pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
497                         pssidtlv->header.len = cpu_to_le16(ssidlen);
498                         memcpy(pssidtlv->ssid, puserscanin->specificSSID,
499                                ssidlen);
500                         ptlvpos += sizeof(pssidtlv->header) + ssidlen;
501                 }
502
503                 /*
504                  *  The default number of channels sent in the command is low to
505                  *    ensure the response buffer from the firmware does not truncate
506                  *    scan results.  That is not an issue with an SSID or BSSID
507                  *    filter applied to the scan results in the firmware.
508                  */
509                 if (ssidlen || (memcmp(pscancfgout->specificBSSID,
510                                        &zeromac, sizeof(zeromac)) != 0)) {
511                         *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
512                         *pfilteredscan = 1;
513                 }
514         } else {
515                 pscancfgout->bsstype = adapter->scanmode;
516                 numprobes = adapter->scanprobes;
517         }
518
519         /* If the input config or adapter has the number of Probes set, add tlv */
520         if (numprobes) {
521                 pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
522                 pnumprobestlv->header.type =
523                     cpu_to_le16(TLV_TYPE_NUMPROBES);
524                 pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes);
525                 pnumprobestlv->numprobes = cpu_to_le16(numprobes);
526
527                 ptlvpos +=
528                     sizeof(pnumprobestlv->header) + pnumprobestlv->header.len;
529
530                 pnumprobestlv->header.len =
531                     cpu_to_le16(pnumprobestlv->header.len);
532         }
533
534         /*
535          * Set the output for the channel TLV to the address in the tlv buffer
536          *   past any TLVs that were added in this fuction (SSID, numprobes).
537          *   channel TLVs will be added past this for each scan command, preserving
538          *   the TLVs that were previously added.
539          */
540         *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
541
542         if (puserscanin && puserscanin->chanlist[0].channumber) {
543
544                 lbs_pr_debug(1, "Scan: Using supplied channel list\n");
545
546                 for (chanidx = 0;
547                      chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
548                      && puserscanin->chanlist[chanidx].channumber; chanidx++) {
549
550                         channel = puserscanin->chanlist[chanidx].channumber;
551                         (pscanchanlist + chanidx)->channumber = channel;
552
553                         radiotype = puserscanin->chanlist[chanidx].radiotype;
554                         (pscanchanlist + chanidx)->radiotype = radiotype;
555
556                         scantype = puserscanin->chanlist[chanidx].scantype;
557
558                         if (scantype == cmd_scan_type_passive) {
559                                 (pscanchanlist +
560                                  chanidx)->chanscanmode.passivescan = 1;
561                         } else {
562                                 (pscanchanlist +
563                                  chanidx)->chanscanmode.passivescan = 0;
564                         }
565
566                         if (puserscanin->chanlist[chanidx].scantime) {
567                                 scandur =
568                                     puserscanin->chanlist[chanidx].scantime;
569                         } else {
570                                 if (scantype == cmd_scan_type_passive) {
571                                         scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
572                                 } else {
573                                         scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
574                                 }
575                         }
576
577                         (pscanchanlist + chanidx)->minscantime =
578                             cpu_to_le16(scandur);
579                         (pscanchanlist + chanidx)->maxscantime =
580                             cpu_to_le16(scandur);
581                 }
582
583                 /* Check if we are only scanning the current channel */
584                 if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
585                                        ==
586                                        priv->adapter->curbssparams.channel)) {
587                         *pscancurrentonly = 1;
588                         lbs_pr_debug(1, "Scan: Scanning current channel only");
589                 }
590
591         } else {
592                 lbs_pr_debug(1, "Scan: Creating full region channel list\n");
593                 wlan_scan_create_channel_list(priv, pscanchanlist,
594                                               *pfilteredscan);
595         }
596
597 out:
598         return pscancfgout;
599 }
600
601 /**
602  *  @brief Construct and send multiple scan config commands to the firmware
603  *
604  *  Previous routines have created a wlan_scan_cmd_config with any requested
605  *   TLVs.  This function splits the channel TLV into maxchanperscan lists
606  *   and sends the portion of the channel TLV along with the other TLVs
607  *   to the wlan_cmd routines for execution in the firmware.
608  *
609  *  @param priv            A pointer to wlan_private structure
610  *  @param maxchanperscan  Maximum number channels to be included in each
611  *                         scan command sent to firmware
612  *  @param filteredscan    Flag indicating whether or not a BSSID or SSID
613  *                         filter is being used for the firmware command
614  *                         scan command sent to firmware
615  *  @param pscancfgout     Scan configuration used for this scan.
616  *  @param pchantlvout     Pointer in the pscancfgout where the channel TLV
617  *                         should start.  This is past any other TLVs that
618  *                         must be sent down in each firmware command.
619  *  @param pscanchanlist   List of channels to scan in maxchanperscan segments
620  *
621  *  @return                0 or error return otherwise
622  */
623 static int wlan_scan_channel_list(wlan_private * priv,
624                                   int maxchanperscan,
625                                   u8 filteredscan,
626                                   struct wlan_scan_cmd_config * pscancfgout,
627                                   struct mrvlietypes_chanlistparamset * pchantlvout,
628                                   struct chanscanparamset * pscanchanlist)
629 {
630         struct chanscanparamset *ptmpchan;
631         struct chanscanparamset *pstartchan;
632         u8 scanband;
633         int doneearly;
634         int tlvidx;
635         int ret = 0;
636
637         ENTER();
638
639         if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
640                 lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n",
641                        pscancfgout, pchantlvout, pscanchanlist);
642                 return -1;
643         }
644
645         pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
646
647         /* Set the temp channel struct pointer to the start of the desired list */
648         ptmpchan = pscanchanlist;
649
650         /* Loop through the desired channel list, sending a new firmware scan
651          *   commands for each maxchanperscan channels (or for 1,6,11 individually
652          *   if configured accordingly)
653          */
654         while (ptmpchan->channumber) {
655
656                 tlvidx = 0;
657                 pchantlvout->header.len = 0;
658                 scanband = ptmpchan->radiotype;
659                 pstartchan = ptmpchan;
660                 doneearly = 0;
661
662                 /* Construct the channel TLV for the scan command.  Continue to
663                  *  insert channel TLVs until:
664                  *    - the tlvidx hits the maximum configured per scan command
665                  *    - the next channel to insert is 0 (end of desired channel list)
666                  *    - doneearly is set (controlling individual scanning of 1,6,11)
667                  */
668                 while (tlvidx < maxchanperscan && ptmpchan->channumber
669                        && !doneearly) {
670
671             lbs_pr_debug(1,
672                     "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
673                 ptmpchan->channumber, ptmpchan->radiotype,
674                 ptmpchan->chanscanmode.passivescan,
675                 ptmpchan->chanscanmode.disablechanfilt,
676                 ptmpchan->maxscantime);
677
678                         /* Copy the current channel TLV to the command being prepared */
679                         memcpy(pchantlvout->chanscanparam + tlvidx,
680                                ptmpchan, sizeof(pchantlvout->chanscanparam));
681
682                         /* Increment the TLV header length by the size appended */
683                         pchantlvout->header.len +=
684                             sizeof(pchantlvout->chanscanparam);
685
686                         /*
687                          *  The tlv buffer length is set to the number of bytes of the
688                          *    between the channel tlv pointer and the start of the
689                          *    tlv buffer.  This compensates for any TLVs that were appended
690                          *    before the channel list.
691                          */
692                         pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
693                                                      - pscancfgout->tlvbuffer);
694
695                         /*  Add the size of the channel tlv header and the data length */
696                         pscancfgout->tlvbufferlen +=
697                             (sizeof(pchantlvout->header)
698                              + pchantlvout->header.len);
699
700                         /* Increment the index to the channel tlv we are constructing */
701                         tlvidx++;
702
703                         doneearly = 0;
704
705                         /* Stop the loop if the *current* channel is in the 1,6,11 set
706                          *   and we are not filtering on a BSSID or SSID.
707                          */
708                         if (!filteredscan && (ptmpchan->channumber == 1
709                                               || ptmpchan->channumber == 6
710                                               || ptmpchan->channumber == 11)) {
711                                 doneearly = 1;
712                         }
713
714                         /* Increment the tmp pointer to the next channel to be scanned */
715                         ptmpchan++;
716
717                         /* Stop the loop if the *next* channel is in the 1,6,11 set.
718                          *  This will cause it to be the only channel scanned on the next
719                          *  interation
720                          */
721                         if (!filteredscan && (ptmpchan->channumber == 1
722                                               || ptmpchan->channumber == 6
723                                               || ptmpchan->channumber == 11)) {
724                                 doneearly = 1;
725                         }
726                 }
727
728                 /* Send the scan command to the firmware with the specified cfg */
729                 ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
730                                             0, 0, pscancfgout);
731         }
732
733         LEAVE();
734         return ret;
735 }
736
737 /**
738  *  @brief Internal function used to start a scan based on an input config
739  *
740  *  Use the input user scan configuration information when provided in
741  *    order to send the appropriate scan commands to firmware to populate or
742  *    update the internal driver scan table
743  *
744  *  @param priv          A pointer to wlan_private structure
745  *  @param puserscanin   Pointer to the input configuration for the requested
746  *                       scan.
747  *
748  *  @return              0 or < 0 if error
749  */
750 int wlan_scan_networks(wlan_private * priv,
751                               const struct wlan_ioctl_user_scan_cfg * puserscanin)
752 {
753         wlan_adapter *adapter = priv->adapter;
754         struct mrvlietypes_chanlistparamset *pchantlvout;
755         struct chanscanparamset * scan_chan_list = NULL;
756         struct wlan_scan_cmd_config * scan_cfg = NULL;
757         u8 keeppreviousscan;
758         u8 filteredscan;
759         u8 scancurrentchanonly;
760         int maxchanperscan;
761         int ret;
762
763         ENTER();
764
765         scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
766                                 WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
767         if (scan_chan_list == NULL) {
768                 ret = -ENOMEM;
769                 goto out;
770         }
771
772         scan_cfg = wlan_scan_setup_scan_config(priv,
773                                                puserscanin,
774                                                &pchantlvout,
775                                                scan_chan_list,
776                                                &maxchanperscan,
777                                                &filteredscan,
778                                                &scancurrentchanonly);
779         if (scan_cfg == NULL) {
780                 ret = -ENOMEM;
781                 goto out;
782         }
783
784         keeppreviousscan = 0;
785
786         if (puserscanin) {
787                 keeppreviousscan = puserscanin->keeppreviousscan;
788         }
789
790         if (!keeppreviousscan) {
791                 memset(adapter->scantable, 0x00,
792                        sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST);
793                 adapter->numinscantable = 0;
794         }
795
796         /* Keep the data path active if we are only scanning our current channel */
797         if (!scancurrentchanonly) {
798                 netif_stop_queue(priv->wlan_dev.netdev);
799                 netif_carrier_off(priv->wlan_dev.netdev);
800         }
801
802         ret = wlan_scan_channel_list(priv,
803                                      maxchanperscan,
804                                      filteredscan,
805                                      scan_cfg,
806                                      pchantlvout,
807                                      scan_chan_list);
808
809         /*  Process the resulting scan table:
810          *    - Remove any bad ssids
811          *    - Update our current BSS information from scan data
812          */
813         wlan_scan_process_results(priv);
814
815         if (priv->adapter->connect_status == libertas_connected) {
816                 netif_carrier_on(priv->wlan_dev.netdev);
817                 netif_wake_queue(priv->wlan_dev.netdev);
818         }
819
820 out:
821         if (scan_cfg)
822                 kfree(scan_cfg);
823
824         if (scan_chan_list)
825                 kfree(scan_chan_list);
826
827         LEAVE();
828         return ret;
829 }
830
831 /**
832  *  @brief Inspect the scan response buffer for pointers to expected TLVs
833  *
834  *  TLVs can be included at the end of the scan response BSS information.
835  *    Parse the data in the buffer for pointers to TLVs that can potentially
836  *    be passed back in the response
837  *
838  *  @param ptlv        Pointer to the start of the TLV buffer to parse
839  *  @param tlvbufsize  size of the TLV buffer
840  *  @param ptsftlv     Output parameter: Pointer to the TSF TLV if found
841  *
842  *  @return            void
843  */
844 static
845 void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
846                                        int tlvbufsize,
847                                        struct mrvlietypes_tsftimestamp ** ptsftlv)
848 {
849         struct mrvlietypes_data *pcurrenttlv;
850         int tlvbufleft;
851         u16 tlvtype;
852         u16 tlvlen;
853
854         pcurrenttlv = ptlv;
855         tlvbufleft = tlvbufsize;
856         *ptsftlv = NULL;
857
858         lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
859         lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
860
861         while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
862                 tlvtype = le16_to_cpu(pcurrenttlv->header.type);
863                 tlvlen = le16_to_cpu(pcurrenttlv->header.len);
864
865                 switch (tlvtype) {
866                 case TLV_TYPE_TSFTIMESTAMP:
867                         *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
868                         break;
869
870                 default:
871                         lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n",
872                                tlvtype);
873                         /* Give up, this seems corrupted */
874                         return;
875                 }               /* switch */
876
877                 tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
878                 pcurrenttlv =
879                     (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
880         }                       /* while */
881 }
882
883 /**
884  *  @brief Interpret a BSS scan response returned from the firmware
885  *
886  *  Parse the various fixed fields and IEs passed back for a a BSS probe
887  *   response or beacon from the scan command.  Record information as needed
888  *   in the scan table struct bss_descriptor for that entry.
889  *
890  *  @param pBSSIDEntry  Output parameter: Pointer to the BSS Entry
891  *
892  *  @return             0 or -1
893  */
894 static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry,
895                                          u8 ** pbeaconinfo, int *bytesleft)
896 {
897         enum ieeetypes_elementid elemID;
898         struct ieeetypes_fhparamset *pFH;
899         struct ieeetypes_dsparamset *pDS;
900         struct ieeetypes_cfparamset *pCF;
901         struct ieeetypes_ibssparamset *pibss;
902         struct ieeetypes_capinfo *pcap;
903         struct WLAN_802_11_FIXED_IEs fixedie;
904         u8 *pcurrentptr;
905         u8 *pRate;
906         u8 elemlen;
907         u8 bytestocopy;
908         u8 ratesize;
909         u16 beaconsize;
910         u8 founddatarateie;
911         int bytesleftforcurrentbeacon;
912
913         struct IE_WPA *pIe;
914         const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
915
916         struct ieeetypes_countryinfoset *pcountryinfo;
917
918         ENTER();
919
920         founddatarateie = 0;
921         ratesize = 0;
922         beaconsize = 0;
923
924         if (*bytesleft >= sizeof(beaconsize)) {
925                 /* Extract & convert beacon size from the command buffer */
926                 memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize));
927                 beaconsize = le16_to_cpu(beaconsize);
928                 *bytesleft -= sizeof(beaconsize);
929                 *pbeaconinfo += sizeof(beaconsize);
930         }
931
932         if (beaconsize == 0 || beaconsize > *bytesleft) {
933
934                 *pbeaconinfo += *bytesleft;
935                 *bytesleft = 0;
936
937                 return -1;
938         }
939
940         /* Initialize the current working beacon pointer for this BSS iteration */
941         pcurrentptr = *pbeaconinfo;
942
943         /* Advance the return beacon pointer past the current beacon */
944         *pbeaconinfo += beaconsize;
945         *bytesleft -= beaconsize;
946
947         bytesleftforcurrentbeacon = beaconsize;
948
949         memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN);
950         lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n",
951                pBSSEntry->macaddress[0], pBSSEntry->macaddress[1],
952                pBSSEntry->macaddress[2], pBSSEntry->macaddress[3],
953                pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]);
954
955         pcurrentptr += ETH_ALEN;
956         bytesleftforcurrentbeacon -= ETH_ALEN;
957
958         if (bytesleftforcurrentbeacon < 12) {
959                 lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n");
960                 return -1;
961         }
962
963         /*
964          * next 4 fields are RSSI, time stamp, beacon interval,
965          *   and capability information
966          */
967
968         /* RSSI is 1 byte long */
969         pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr));
970         lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr);
971         pcurrentptr += 1;
972         bytesleftforcurrentbeacon -= 1;
973
974         /* time stamp is 8 bytes long */
975         memcpy(fixedie.timestamp, pcurrentptr, 8);
976         memcpy(pBSSEntry->timestamp, pcurrentptr, 8);
977         pcurrentptr += 8;
978         bytesleftforcurrentbeacon -= 8;
979
980         /* beacon interval is 2 bytes long */
981         memcpy(&fixedie.beaconinterval, pcurrentptr, 2);
982         pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval);
983         pcurrentptr += 2;
984         bytesleftforcurrentbeacon -= 2;
985
986         /* capability information is 2 bytes long */
987         memcpy(&fixedie.capabilities, pcurrentptr, 2);
988         lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n",
989                fixedie.capabilities);
990         fixedie.capabilities = le16_to_cpu(fixedie.capabilities);
991         pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
992         memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo));
993         pcurrentptr += 2;
994         bytesleftforcurrentbeacon -= 2;
995
996         /* rest of the current buffer are IE's */
997         lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n",
998                bytesleftforcurrentbeacon);
999
1000         lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr,
1001                 bytesleftforcurrentbeacon);
1002
1003         if (pcap->privacy) {
1004                 lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n");
1005                 pBSSEntry->privacy = wlan802_11privfilter8021xWEP;
1006         } else {
1007                 pBSSEntry->privacy = wlan802_11privfilteracceptall;
1008         }
1009
1010         if (pcap->ibss == 1) {
1011                 pBSSEntry->inframode = wlan802_11ibss;
1012         } else {
1013                 pBSSEntry->inframode = wlan802_11infrastructure;
1014         }
1015
1016         /* process variable IE */
1017         while (bytesleftforcurrentbeacon >= 2) {
1018                 elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
1019                 elemlen = *((u8 *) pcurrentptr + 1);
1020
1021                 if (bytesleftforcurrentbeacon < elemlen) {
1022                         lbs_pr_debug(1, "InterpretIE: error in processing IE, "
1023                                "bytes left < IE length\n");
1024                         bytesleftforcurrentbeacon = 0;
1025                         continue;
1026                 }
1027
1028                 switch (elemID) {
1029
1030                 case SSID:
1031                         pBSSEntry->ssid.ssidlength = elemlen;
1032                         memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2),
1033                                elemlen);
1034                         lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid);
1035                         break;
1036
1037                 case SUPPORTED_RATES:
1038                         memcpy(pBSSEntry->datarates, (pcurrentptr + 2),
1039                                elemlen);
1040                         memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2),
1041                                 elemlen);
1042                         ratesize = elemlen;
1043                         founddatarateie = 1;
1044                         break;
1045
1046                 case EXTRA_IE:
1047                         lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n");
1048                         pBSSEntry->extra_ie = 1;
1049                         break;
1050
1051                 case FH_PARAM_SET:
1052                         pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
1053                         memmove(&pBSSEntry->phyparamset.fhparamset, pFH,
1054                                 sizeof(struct ieeetypes_fhparamset));
1055                         pBSSEntry->phyparamset.fhparamset.dwelltime
1056                             =
1057                             le16_to_cpu(pBSSEntry->phyparamset.fhparamset.
1058                                              dwelltime);
1059                         break;
1060
1061                 case DS_PARAM_SET:
1062                         pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
1063
1064                         pBSSEntry->channel = pDS->currentchan;
1065
1066                         memcpy(&pBSSEntry->phyparamset.dsparamset, pDS,
1067                                sizeof(struct ieeetypes_dsparamset));
1068                         break;
1069
1070                 case CF_PARAM_SET:
1071                         pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
1072
1073                         memcpy(&pBSSEntry->ssparamset.cfparamset, pCF,
1074                                sizeof(struct ieeetypes_cfparamset));
1075                         break;
1076
1077                 case IBSS_PARAM_SET:
1078                         pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
1079                         pBSSEntry->atimwindow =
1080                             le32_to_cpu(pibss->atimwindow);
1081
1082                         memmove(&pBSSEntry->ssparamset.ibssparamset, pibss,
1083                                 sizeof(struct ieeetypes_ibssparamset));
1084
1085                         pBSSEntry->ssparamset.ibssparamset.atimwindow
1086                             =
1087                             le16_to_cpu(pBSSEntry->ssparamset.ibssparamset.
1088                                              atimwindow);
1089                         break;
1090
1091                         /* Handle Country Info IE */
1092                 case COUNTRY_INFO:
1093                         pcountryinfo =
1094                             (struct ieeetypes_countryinfoset *) pcurrentptr;
1095
1096                         if (pcountryinfo->len <
1097                             sizeof(pcountryinfo->countrycode)
1098                             || pcountryinfo->len > 254) {
1099                                 lbs_pr_debug(1, "InterpretIE: 11D- Err "
1100                                        "CountryInfo len =%d min=%d max=254\n",
1101                                        pcountryinfo->len,
1102                                        sizeof(pcountryinfo->countrycode));
1103                                 LEAVE();
1104                                 return -1;
1105                         }
1106
1107                         memcpy(&pBSSEntry->countryinfo,
1108                                pcountryinfo, pcountryinfo->len + 2);
1109                         lbs_dbg_hex("InterpretIE: 11D- CountryInfo:",
1110                                 (u8 *) pcountryinfo,
1111                                 (u32) (pcountryinfo->len + 2));
1112                         break;
1113
1114                 case EXTENDED_SUPPORTED_RATES:
1115                         /*
1116                          * only process extended supported rate
1117                          * if data rate is already found.
1118                          * data rate IE should come before
1119                          * extended supported rate IE
1120                          */
1121                         if (founddatarateie) {
1122                                 if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
1123                                         bytestocopy =
1124                                             (WLAN_SUPPORTED_RATES - ratesize);
1125                                 } else {
1126                                         bytestocopy = elemlen;
1127                                 }
1128
1129                                 pRate = (u8 *) pBSSEntry->datarates;
1130                                 pRate += ratesize;
1131                                 memmove(pRate, (pcurrentptr + 2), bytestocopy);
1132
1133                                 pRate = (u8 *) pBSSEntry->libertas_supported_rates;
1134
1135                                 pRate += ratesize;
1136                                 memmove(pRate, (pcurrentptr + 2), bytestocopy);
1137                         }
1138                         break;
1139
1140                 case VENDOR_SPECIFIC_221:
1141 #define IE_ID_LEN_FIELDS_BYTES 2
1142                         pIe = (struct IE_WPA *)pcurrentptr;
1143
1144                         if (memcmp(pIe->oui, oui01, sizeof(oui01)))
1145                                 break;
1146
1147                         pBSSEntry->wpa_ie_len = min_t(size_t,
1148                                 elemlen + IE_ID_LEN_FIELDS_BYTES,
1149                                 sizeof(pBSSEntry->wpa_ie));
1150                         memcpy(pBSSEntry->wpa_ie, pcurrentptr,
1151                                 pBSSEntry->wpa_ie_len);
1152                         lbs_dbg_hex("InterpretIE: Resp WPA_IE",
1153                                 pBSSEntry->wpa_ie, elemlen);
1154                         break;
1155                 case WPA2_IE:
1156                         pIe = (struct IE_WPA *)pcurrentptr;
1157
1158                         pBSSEntry->rsn_ie_len = min_t(size_t,
1159                                 elemlen + IE_ID_LEN_FIELDS_BYTES,
1160                                 sizeof(pBSSEntry->rsn_ie));
1161                         memcpy(pBSSEntry->rsn_ie, pcurrentptr,
1162                                 pBSSEntry->rsn_ie_len);
1163                         lbs_dbg_hex("InterpretIE: Resp WPA2_IE",
1164                                 pBSSEntry->rsn_ie, elemlen);
1165                         break;
1166                 case TIM:
1167                         break;
1168
1169                 case CHALLENGE_TEXT:
1170                         break;
1171                 }
1172
1173                 pcurrentptr += elemlen + 2;
1174
1175                 /* need to account for IE ID and IE len */
1176                 bytesleftforcurrentbeacon -= (elemlen + 2);
1177
1178         }                       /* while (bytesleftforcurrentbeacon > 2) */
1179
1180         return 0;
1181 }
1182
1183 /**
1184  *  @brief Compare two SSIDs
1185  *
1186  *  @param ssid1    A pointer to ssid to compare
1187  *  @param ssid2    A pointer to ssid to compare
1188  *
1189  *  @return         0--ssid is same, otherwise is different
1190  */
1191 int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2)
1192 {
1193         if (!ssid1 || !ssid2)
1194                 return -1;
1195
1196         if (ssid1->ssidlength != ssid2->ssidlength)
1197                 return -1;
1198
1199         return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength);
1200 }
1201
1202 /**
1203  *  @brief This function finds a specific compatible BSSID in the scan list
1204  *
1205  *  @param adapter  A pointer to wlan_adapter
1206  *  @param bssid    BSSID to find in the scan list
1207  *  @param mode     Network mode: Infrastructure or IBSS
1208  *
1209  *  @return         index in BSSID list, or error return code (< 0)
1210  */
1211 int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode)
1212 {
1213         int ret = -ENETUNREACH;
1214         int i;
1215
1216         if (!bssid)
1217                 return -EFAULT;
1218
1219         lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n",
1220                adapter->numinscantable);
1221
1222         /* Look through the scan table for a compatible match. The ret return
1223          *   variable will be equal to the index in the scan table (greater
1224          *   than zero) if the network is compatible.  The loop will continue
1225          *   past a matched bssid that is not compatible in case there is an
1226          *   AP with multiple SSIDs assigned to the same BSSID
1227          */
1228         for (i = 0; ret < 0 && i < adapter->numinscantable; i++) {
1229                 if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) {
1230                         switch (mode) {
1231                         case wlan802_11infrastructure:
1232                         case wlan802_11ibss:
1233                                 ret = is_network_compatible(adapter, i, mode);
1234                                 break;
1235                         default:
1236                                 ret = i;
1237                                 break;
1238                         }
1239                 }
1240         }
1241
1242         return ret;
1243 }
1244
1245 /**
1246  *  @brief This function finds ssid in ssid list.
1247  *
1248  *  @param adapter  A pointer to wlan_adapter
1249  *  @param ssid     SSID to find in the list
1250  *  @param bssid    BSSID to qualify the SSID selection (if provided)
1251  *  @param mode     Network mode: Infrastructure or IBSS
1252  *
1253  *  @return         index in BSSID list
1254  */
1255 int libertas_find_SSID_in_list(wlan_adapter * adapter,
1256                    struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode)
1257 {
1258         int net = -ENETUNREACH;
1259         u8 bestrssi = 0;
1260         int i;
1261         int j;
1262
1263         lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable);
1264
1265         for (i = 0; i < adapter->numinscantable; i++) {
1266                 if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) &&
1267                     (!bssid ||
1268                      !memcmp(adapter->scantable[i].
1269                              macaddress, bssid, ETH_ALEN))) {
1270                         switch (mode) {
1271                         case wlan802_11infrastructure:
1272                         case wlan802_11ibss:
1273                                 j = is_network_compatible(adapter, i, mode);
1274
1275                                 if (j >= 0) {
1276                                         if (bssid) {
1277                                                 return i;
1278                                         }
1279
1280                                         if (SCAN_RSSI
1281                                             (adapter->scantable[i].rssi)
1282                                             > bestrssi) {
1283                                                 bestrssi =
1284                                                     SCAN_RSSI(adapter->
1285                                                               scantable[i].
1286                                                               rssi);
1287                                                 net = i;
1288                                         }
1289                                 } else {
1290                                         if (net == -ENETUNREACH) {
1291                                                 net = j;
1292                                         }
1293                                 }
1294                                 break;
1295                         case wlan802_11autounknown:
1296                         default:
1297                                 if (SCAN_RSSI(adapter->scantable[i].rssi)
1298                                     > bestrssi) {
1299                                         bestrssi =
1300                                             SCAN_RSSI(adapter->scantable[i].
1301                                                       rssi);
1302                                         net = i;
1303                                 }
1304                                 break;
1305                         }
1306                 }
1307         }
1308
1309         return net;
1310 }
1311
1312 /**
1313  *  @brief This function finds the best SSID in the Scan List
1314  *
1315  *  Search the scan table for the best SSID that also matches the current
1316  *   adapter network preference (infrastructure or adhoc)
1317  *
1318  *  @param adapter  A pointer to wlan_adapter
1319  *
1320  *  @return         index in BSSID list
1321  */
1322 int libertas_find_best_SSID_in_list(wlan_adapter * adapter,
1323                                     enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode)
1324 {
1325         int bestnet = -ENETUNREACH;
1326         u8 bestrssi = 0;
1327         int i;
1328
1329         ENTER();
1330
1331         lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable);
1332
1333         for (i = 0; i < adapter->numinscantable; i++) {
1334                 switch (mode) {
1335                 case wlan802_11infrastructure:
1336                 case wlan802_11ibss:
1337                         if (is_network_compatible(adapter, i, mode) >= 0) {
1338                                 if (SCAN_RSSI(adapter->scantable[i].rssi) >
1339                                     bestrssi) {
1340                                         bestrssi =
1341                                             SCAN_RSSI(adapter->scantable[i].
1342                                                       rssi);
1343                                         bestnet = i;
1344                                 }
1345                         }
1346                         break;
1347                 case wlan802_11autounknown:
1348                 default:
1349                         if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) {
1350                                 bestrssi =
1351                                     SCAN_RSSI(adapter->scantable[i].rssi);
1352                                 bestnet = i;
1353                         }
1354                         break;
1355                 }
1356         }
1357
1358         LEAVE();
1359         return bestnet;
1360 }
1361
1362 /**
1363  *  @brief Find the AP with specific ssid in the scan list
1364  *
1365  *  @param priv         A pointer to wlan_private structure
1366  *  @param pSSID        A pointer to AP's ssid
1367  *
1368  *  @return             0--success, otherwise--fail
1369  */
1370 int libertas_find_best_network_SSID(wlan_private * priv,
1371                                     struct WLAN_802_11_SSID *pSSID,
1372                                     enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
1373                                     enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode)
1374 {
1375         wlan_adapter *adapter = priv->adapter;
1376         int ret = 0;
1377         struct bss_descriptor *preqbssid;
1378         int i;
1379
1380         ENTER();
1381
1382         memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
1383
1384         wlan_scan_networks(priv, NULL);
1385         if (adapter->surpriseremoved)
1386                 return -1;
1387         wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
1388
1389         i = libertas_find_best_SSID_in_list(adapter, preferred_mode);
1390         if (i < 0) {
1391                 ret = -1;
1392                 goto out;
1393         }
1394
1395         preqbssid = &adapter->scantable[i];
1396         memcpy(pSSID, &preqbssid->ssid,
1397                sizeof(struct WLAN_802_11_SSID));
1398         *out_mode = preqbssid->inframode;
1399
1400         if (!pSSID->ssidlength) {
1401                 ret = -1;
1402         }
1403
1404 out:
1405         LEAVE();
1406         return ret;
1407 }
1408
1409 /**
1410  *  @brief Scan Network
1411  *
1412  *  @param dev          A pointer to net_device structure
1413  *  @param info         A pointer to iw_request_info structure
1414  *  @param vwrq         A pointer to iw_param structure
1415  *  @param extra        A pointer to extra data buf
1416  *
1417  *  @return             0 --success, otherwise fail
1418  */
1419 int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
1420                   struct iw_param *vwrq, char *extra)
1421 {
1422         wlan_private *priv = dev->priv;
1423         wlan_adapter *adapter = priv->adapter;
1424         union iwreq_data wrqu;
1425
1426         ENTER();
1427
1428         if (!wlan_scan_networks(priv, NULL)) {
1429                 memset(&wrqu, 0, sizeof(union iwreq_data));
1430                 wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
1431                                     NULL);
1432         }
1433
1434         if (adapter->surpriseremoved)
1435                 return -1;
1436
1437         LEAVE();
1438         return 0;
1439 }
1440
1441 /**
1442  *  @brief Send a scan command for all available channels filtered on a spec
1443  *
1444  *  @param priv             A pointer to wlan_private structure
1445  *  @param prequestedssid   A pointer to AP's ssid
1446  *  @param keeppreviousscan Flag used to save/clear scan table before scan
1447  *
1448  *  @return                0-success, otherwise fail
1449  */
1450 int libertas_send_specific_SSID_scan(wlan_private * priv,
1451                          struct WLAN_802_11_SSID *prequestedssid,
1452                          u8 keeppreviousscan)
1453 {
1454         wlan_adapter *adapter = priv->adapter;
1455         struct wlan_ioctl_user_scan_cfg scancfg;
1456
1457         ENTER();
1458
1459         if (prequestedssid == NULL) {
1460                 return -1;
1461         }
1462
1463         memset(&scancfg, 0x00, sizeof(scancfg));
1464
1465         memcpy(scancfg.specificSSID, prequestedssid->ssid,
1466                prequestedssid->ssidlength);
1467         scancfg.keeppreviousscan = keeppreviousscan;
1468
1469         wlan_scan_networks(priv, &scancfg);
1470         if (adapter->surpriseremoved)
1471                 return -1;
1472         wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
1473
1474         LEAVE();
1475         return 0;
1476 }
1477
1478 /**
1479  *  @brief scan an AP with specific BSSID
1480  *
1481  *  @param priv             A pointer to wlan_private structure
1482  *  @param bssid            A pointer to AP's bssid
1483  *  @param keeppreviousscan Flag used to save/clear scan table before scan
1484  *
1485  *  @return          0-success, otherwise fail
1486  */
1487 int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan)
1488 {
1489         struct wlan_ioctl_user_scan_cfg scancfg;
1490
1491         ENTER();
1492
1493         if (bssid == NULL) {
1494                 return -1;
1495         }
1496
1497         memset(&scancfg, 0x00, sizeof(scancfg));
1498         memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
1499         scancfg.keeppreviousscan = keeppreviousscan;
1500
1501         wlan_scan_networks(priv, &scancfg);
1502         if (priv->adapter->surpriseremoved)
1503                 return -1;
1504         wait_event_interruptible(priv->adapter->cmd_pending,
1505                 !priv->adapter->nr_cmd_pending);
1506
1507         LEAVE();
1508         return 0;
1509 }
1510
1511 /**
1512  *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
1513  *
1514  *  @param dev          A pointer to net_device structure
1515  *  @param info         A pointer to iw_request_info structure
1516  *  @param dwrq         A pointer to iw_point structure
1517  *  @param extra        A pointer to extra data buf
1518  *
1519  *  @return             0 --success, otherwise fail
1520  */
1521 int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
1522                   struct iw_point *dwrq, char *extra)
1523 {
1524         wlan_private *priv = dev->priv;
1525         wlan_adapter *adapter = priv->adapter;
1526         int ret = 0;
1527         char *current_ev = extra;
1528         char *end_buf = extra + IW_SCAN_MAX_DATA;
1529         struct chan_freq_power *cfp;
1530         struct bss_descriptor *pscantable;
1531         char *current_val;      /* For rates */
1532         struct iw_event iwe;    /* Temporary buffer */
1533         int i;
1534         int j;
1535         int rate;
1536 #define PERFECT_RSSI ((u8)50)
1537 #define WORST_RSSI   ((u8)0)
1538 #define RSSI_DIFF    ((u8)(PERFECT_RSSI - WORST_RSSI))
1539         u8 rssi;
1540
1541         u8 buf[16 + 256 * 2];
1542         u8 *ptr;
1543
1544         ENTER();
1545
1546         /*
1547          * if there's either commands in the queue or one being
1548          * processed return -EAGAIN for iwlist to retry later.
1549          */
1550     if (adapter->nr_cmd_pending)
1551                 return -EAGAIN;
1552
1553         if (adapter->connect_status == libertas_connected)
1554                 lbs_pr_debug(1, "Current ssid: %32s\n",
1555                        adapter->curbssparams.ssid.ssid);
1556
1557         lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n",
1558                adapter->numinscantable);
1559
1560         /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
1561          * The new API using SIOCGIWSCAN is only limited by buffer size
1562          * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
1563          * which is 4096.
1564          */
1565         for (i = 0; i < adapter->numinscantable; i++) {
1566                 if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
1567                         lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p "
1568                                "MAX_SCAN_CELL_SIZE=%d\n",
1569                                i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
1570                         break;
1571                 }
1572
1573                 pscantable = &adapter->scantable[i];
1574
1575                 lbs_pr_debug(1, "i=%d  ssid: %32s\n", i, pscantable->ssid.ssid);
1576
1577                 cfp =
1578                     libertas_find_cfp_by_band_and_channel(adapter, 0,
1579                                                  pscantable->channel);
1580                 if (!cfp) {
1581                         lbs_pr_debug(1, "Invalid channel number %d\n",
1582                                pscantable->channel);
1583                         continue;
1584                 }
1585
1586                 if (!ssid_valid(&adapter->scantable[i].ssid)) {
1587                         continue;
1588                 }
1589
1590                 /* First entry *MUST* be the AP MAC address */
1591                 iwe.cmd = SIOCGIWAP;
1592                 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1593                 memcpy(iwe.u.ap_addr.sa_data,
1594                        &adapter->scantable[i].macaddress, ETH_ALEN);
1595
1596                 iwe.len = IW_EV_ADDR_LEN;
1597                 current_ev =
1598                     iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1599
1600                 //Add the ESSID
1601                 iwe.u.data.length = adapter->scantable[i].ssid.ssidlength;
1602
1603                 if (iwe.u.data.length > 32) {
1604                         iwe.u.data.length = 32;
1605                 }
1606
1607                 iwe.cmd = SIOCGIWESSID;
1608                 iwe.u.data.flags = 1;
1609                 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1610                 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
1611                                                   adapter->scantable[i].ssid.
1612                                                   ssid);
1613
1614                 //Add mode
1615                 iwe.cmd = SIOCGIWMODE;
1616                 iwe.u.mode = adapter->scantable[i].inframode + 1;
1617                 iwe.len = IW_EV_UINT_LEN;
1618                 current_ev =
1619                     iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1620
1621                 //frequency
1622                 iwe.cmd = SIOCGIWFREQ;
1623                 iwe.u.freq.m = (long)cfp->freq * 100000;
1624                 iwe.u.freq.e = 1;
1625                 iwe.len = IW_EV_FREQ_LEN;
1626                 current_ev =
1627                     iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1628
1629                 /* Add quality statistics */
1630                 iwe.cmd = IWEVQUAL;
1631                 iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
1632                 iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi);
1633
1634                 rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
1635                 iwe.u.qual.qual =
1636                     (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
1637                      (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
1638                     (RSSI_DIFF * RSSI_DIFF);
1639                 if (iwe.u.qual.qual > 100)
1640                         iwe.u.qual.qual = 100;
1641                 else if (iwe.u.qual.qual < 1)
1642                         iwe.u.qual.qual = 0;
1643
1644                 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
1645                         iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
1646                 } else {
1647                         iwe.u.qual.noise =
1648                             CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
1649                 }
1650                 if ((adapter->inframode == wlan802_11ibss) &&
1651                     !libertas_SSID_cmp(&adapter->curbssparams.ssid,
1652                              &adapter->scantable[i].ssid)
1653                     && adapter->adhoccreate) {
1654                         ret = libertas_prepare_and_send_command(priv,
1655                                                     cmd_802_11_rssi,
1656                                                     0,
1657                                                     cmd_option_waitforrsp,
1658                                                     0, NULL);
1659
1660                         if (!ret) {
1661                                 iwe.u.qual.level =
1662                                     CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] /
1663                                              AVG_SCALE,
1664                                              adapter->NF[TYPE_RXPD][TYPE_AVG] /
1665                                              AVG_SCALE);
1666                         }
1667                 }
1668                 iwe.len = IW_EV_QUAL_LEN;
1669                 current_ev =
1670                     iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
1671
1672                 /* Add encryption capability */
1673                 iwe.cmd = SIOCGIWENCODE;
1674                 if (adapter->scantable[i].privacy) {
1675                         iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1676                 } else {
1677                         iwe.u.data.flags = IW_ENCODE_DISABLED;
1678                 }
1679                 iwe.u.data.length = 0;
1680                 iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1681                 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
1682                                                   adapter->scantable->ssid.
1683                                                   ssid);
1684
1685                 current_val = current_ev + IW_EV_LCP_LEN;
1686
1687                 iwe.cmd = SIOCGIWRATE;
1688
1689                 iwe.u.bitrate.fixed = 0;
1690                 iwe.u.bitrate.disabled = 0;
1691                 iwe.u.bitrate.value = 0;
1692
1693                 /* Bit rate given in 500 kb/s units (+ 0x80) */
1694                 for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates);
1695                      j++) {
1696                         if (adapter->scantable[i].libertas_supported_rates[j] == 0) {
1697                                 break;
1698                         }
1699                         rate =
1700                             (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) *
1701                             500000;
1702                         if (rate > iwe.u.bitrate.value) {
1703                                 iwe.u.bitrate.value = rate;
1704                         }
1705
1706                         iwe.u.bitrate.value =
1707                             (adapter->scantable[i].libertas_supported_rates[j]
1708                              & 0x7f) * 500000;
1709                         iwe.len = IW_EV_PARAM_LEN;
1710                         current_ev =
1711                             iwe_stream_add_value(current_ev, current_val,
1712                                                  end_buf, &iwe, iwe.len);
1713
1714                 }
1715                 if ((adapter->scantable[i].inframode == wlan802_11ibss)
1716                     && !libertas_SSID_cmp(&adapter->curbssparams.ssid,
1717                                 &adapter->scantable[i].ssid)
1718                     && adapter->adhoccreate) {
1719                         iwe.u.bitrate.value = 22 * 500000;
1720                 }
1721                 iwe.len = IW_EV_PARAM_LEN;
1722                 current_ev =
1723                     iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
1724                                          iwe.len);
1725
1726                 /* Add new value to event */
1727                 current_val = current_ev + IW_EV_LCP_LEN;
1728
1729                 if (adapter->scantable[i].rsn_ie[0] == WPA2_IE) {
1730                         memset(&iwe, 0, sizeof(iwe));
1731                         memset(buf, 0, sizeof(buf));
1732                         memcpy(buf, adapter->scantable[i].rsn_ie,
1733                                         adapter->scantable[i].rsn_ie_len);
1734                         iwe.cmd = IWEVGENIE;
1735                         iwe.u.data.length = adapter->scantable[i].rsn_ie_len;
1736                         iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1737                         current_ev = iwe_stream_add_point(current_ev, end_buf,
1738                                         &iwe, buf);
1739                 }
1740                 if (adapter->scantable[i].wpa_ie[0] == WPA_IE) {
1741                         memset(&iwe, 0, sizeof(iwe));
1742                         memset(buf, 0, sizeof(buf));
1743                         memcpy(buf, adapter->scantable[i].wpa_ie,
1744                                         adapter->scantable[i].wpa_ie_len);
1745                         iwe.cmd = IWEVGENIE;
1746                         iwe.u.data.length = adapter->scantable[i].wpa_ie_len;
1747                         iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1748                         current_ev = iwe_stream_add_point(current_ev, end_buf,
1749                                         &iwe, buf);
1750                 }
1751
1752
1753                 if (adapter->scantable[i].extra_ie != 0) {
1754                         memset(&iwe, 0, sizeof(iwe));
1755                         memset(buf, 0, sizeof(buf));
1756                         ptr = buf;
1757                         ptr += sprintf(ptr, "extra_ie");
1758                         iwe.u.data.length = strlen(buf);
1759
1760                         lbs_pr_debug(1, "iwe.u.data.length %d\n",
1761                                iwe.u.data.length);
1762                         lbs_pr_debug(1, "BUF: %s \n", buf);
1763
1764                         iwe.cmd = IWEVCUSTOM;
1765                         iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
1766                         current_ev =
1767                             iwe_stream_add_point(current_ev, end_buf, &iwe,
1768                                                  buf);
1769                 }
1770
1771                 current_val = current_ev + IW_EV_LCP_LEN;
1772
1773                 /*
1774                  * Check if we added any event
1775                  */
1776                 if ((current_val - current_ev) > IW_EV_LCP_LEN)
1777                         current_ev = current_val;
1778         }
1779
1780         dwrq->length = (current_ev - extra);
1781         dwrq->flags = 0;
1782
1783         LEAVE();
1784         return 0;
1785 }
1786
1787 /**
1788  *  @brief Prepare a scan command to be sent to the firmware
1789  *
1790  *  Use the wlan_scan_cmd_config sent to the command processing module in
1791  *   the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
1792  *   struct to send to firmware.
1793  *
1794  *  The fixed fields specifying the BSS type and BSSID filters as well as a
1795  *   variable number/length of TLVs are sent in the command to firmware.
1796  *
1797  *  @param priv       A pointer to wlan_private structure
1798  *  @param cmd        A pointer to cmd_ds_command structure to be sent to
1799  *                    firmware with the cmd_DS_801_11_SCAN structure
1800  *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
1801  *                    to set the fields/TLVs for the command sent to firmware
1802  *
1803  *  @return           0 or -1
1804  *
1805  *  @sa wlan_scan_create_channel_list
1806  */
1807 int libertas_cmd_80211_scan(wlan_private * priv,
1808                          struct cmd_ds_command *cmd, void *pdata_buf)
1809 {
1810         struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
1811         struct wlan_scan_cmd_config *pscancfg;
1812
1813         ENTER();
1814
1815         pscancfg = pdata_buf;
1816
1817         /* Set fixed field variables in scan command */
1818         pscan->bsstype = pscancfg->bsstype;
1819         memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID));
1820         memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
1821
1822         cmd->command = cpu_to_le16(cmd_802_11_scan);
1823
1824         /* size is equal to the sizeof(fixed portions) + the TLV len + header */
1825         cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
1826                                      + sizeof(pscan->BSSID)
1827                                      + pscancfg->tlvbufferlen + S_DS_GEN);
1828
1829         lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
1830                cmd->command, cmd->size, cmd->seqnum);
1831         LEAVE();
1832         return 0;
1833 }
1834
1835 /**
1836  *  @brief This function handles the command response of scan
1837  *
1838  *   The response buffer for the scan command has the following
1839  *      memory layout:
1840  *
1841  *     .-----------------------------------------------------------.
1842  *     |  header (4 * sizeof(u16)):  Standard command response hdr |
1843  *     .-----------------------------------------------------------.
1844  *     |  bufsize (u16) : sizeof the BSS Description data          |
1845  *     .-----------------------------------------------------------.
1846  *     |  NumOfSet (u8) : Number of BSS Descs returned             |
1847  *     .-----------------------------------------------------------.
1848  *     |  BSSDescription data (variable, size given in bufsize)    |
1849  *     .-----------------------------------------------------------.
1850  *     |  TLV data (variable, size calculated using header->size,  |
1851  *     |            bufsize and sizeof the fixed fields above)     |
1852  *     .-----------------------------------------------------------.
1853  *
1854  *  @param priv    A pointer to wlan_private structure
1855  *  @param resp    A pointer to cmd_ds_command
1856  *
1857  *  @return        0 or -1
1858  */
1859 int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
1860 {
1861         wlan_adapter *adapter = priv->adapter;
1862         struct cmd_ds_802_11_scan_rsp *pscan;
1863         struct bss_descriptor newbssentry;
1864         struct mrvlietypes_data *ptlv;
1865         struct mrvlietypes_tsftimestamp *ptsftlv;
1866         u8 *pbssinfo;
1867         u16 scanrespsize;
1868         int bytesleft;
1869         int numintable;
1870         int bssIdx;
1871         int idx;
1872         int tlvbufsize;
1873         u64 tsfval;
1874
1875         ENTER();
1876
1877         pscan = &resp->params.scanresp;
1878
1879         if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) {
1880         lbs_pr_debug(1,
1881                        "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
1882                        pscan->nr_sets);
1883                 LEAVE();
1884                 return -1;
1885         }
1886
1887         bytesleft = le16_to_cpu(pscan->bssdescriptsize);
1888         lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft);
1889
1890         scanrespsize = le16_to_cpu(resp->size);
1891         lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n",
1892                pscan->nr_sets);
1893
1894         numintable = adapter->numinscantable;
1895         pbssinfo = pscan->bssdesc_and_tlvbuffer;
1896
1897         /* The size of the TLV buffer is equal to the entire command response
1898          *   size (scanrespsize) minus the fixed fields (sizeof()'s), the
1899          *   BSS Descriptions (bssdescriptsize as bytesLef) and the command
1900          *   response header (S_DS_GEN)
1901          */
1902         tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize)
1903                                      + sizeof(pscan->nr_sets)
1904                                      + S_DS_GEN);
1905
1906         ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
1907
1908         /* Search the TLV buffer space in the scan response for any valid TLVs */
1909         wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
1910
1911         /*
1912          *  Process each scan response returned (pscan->nr_sets).  Save
1913          *    the information in the newbssentry and then insert into the
1914          *    driver scan table either as an update to an existing entry
1915          *    or as an addition at the end of the table
1916          */
1917         for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) {
1918                 /* Zero out the newbssentry we are about to store info in */
1919                 memset(&newbssentry, 0x00, sizeof(newbssentry));
1920
1921                 /* Process the data fields and IEs returned for this BSS */
1922                 if ((InterpretBSSDescriptionWithIE(&newbssentry,
1923                                                    &pbssinfo,
1924                                                    &bytesleft) ==
1925                      0)
1926                     && CHECK_SSID_IS_VALID(&newbssentry.ssid)) {
1927
1928             lbs_pr_debug(1,
1929                                "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
1930                                newbssentry.macaddress[0],
1931                                newbssentry.macaddress[1],
1932                                newbssentry.macaddress[2],
1933                                newbssentry.macaddress[3],
1934                                newbssentry.macaddress[4],
1935                                newbssentry.macaddress[5]);
1936
1937                         /*
1938                          * Search the scan table for the same bssid
1939                          */
1940                         for (bssIdx = 0; bssIdx < numintable; bssIdx++) {
1941                                 if (memcmp(newbssentry.macaddress,
1942                                            adapter->scantable[bssIdx].
1943                                            macaddress,
1944                                            sizeof(newbssentry.macaddress)) ==
1945                                     0) {
1946                                         /*
1947                                          * If the SSID matches as well, it is a duplicate of
1948                                          *   this entry.  Keep the bssIdx set to this
1949                                          *   entry so we replace the old contents in the table
1950                                          */
1951                                         if ((newbssentry.ssid.ssidlength ==
1952                                              adapter->scantable[bssIdx].ssid.
1953                                              ssidlength)
1954                                             &&
1955                                             (memcmp
1956                                              (newbssentry.ssid.ssid,
1957                                               adapter->scantable[bssIdx].ssid.
1958                                               ssid,
1959                                               newbssentry.ssid.ssidlength) ==
1960                                              0)) {
1961                         lbs_pr_debug(1,
1962                                                        "SCAN_RESP: Duplicate of index: %d\n",
1963                                                        bssIdx);
1964                                                 break;
1965                                         }
1966                                 }
1967                         }
1968                         /*
1969                          * If the bssIdx is equal to the number of entries in the table,
1970                          *   the new entry was not a duplicate; append it to the scan
1971                          *   table
1972                          */
1973                         if (bssIdx == numintable) {
1974                                 /* Range check the bssIdx, keep it limited to the last entry */
1975                                 if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
1976                                         bssIdx--;
1977                                 } else {
1978                                         numintable++;
1979                                 }
1980                         }
1981
1982                         /*
1983                          * If the TSF TLV was appended to the scan results, save the
1984                          *   this entries TSF value in the networktsf field.  The
1985                          *   networktsf is the firmware's TSF value at the time the
1986                          *   beacon or probe response was received.
1987                          */
1988                         if (ptsftlv) {
1989                                 memcpy(&tsfval, &ptsftlv->tsftable[idx],
1990                                        sizeof(tsfval));
1991                                 tsfval = le64_to_cpu(tsfval);
1992
1993                                 memcpy(&newbssentry.networktsf,
1994                                        &tsfval, sizeof(newbssentry.networktsf));
1995                         }
1996
1997                         /* Copy the locally created newbssentry to the scan table */
1998                         memcpy(&adapter->scantable[bssIdx],
1999                                &newbssentry,
2000                                sizeof(adapter->scantable[bssIdx]));
2001
2002                 } else {
2003
2004                         /* error parsing/interpreting the scan response, skipped */
2005                         lbs_pr_debug(1, "SCAN_RESP: "
2006                                "InterpretBSSDescriptionWithIE returned ERROR\n");
2007                 }
2008         }
2009
2010         lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
2011                pscan->nr_sets, numintable - adapter->numinscantable,
2012                numintable);
2013
2014         /* Update the total number of BSSIDs in the scan table */
2015         adapter->numinscantable = numintable;
2016
2017         LEAVE();
2018         return 0;
2019 }