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