1 /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */
4 * Copyright (c) 2014 genua mbh <info@genua.de>
5 * Copyright (c) 2014 Fixup Software Ltd.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Based on BSD-licensed source modules in the Linux iwlwifi driver,
22 * which were used as the reference documentation for this implementation.
24 * Driver version we are currently based off of is
25 * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd)
27 ***********************************************************************
29 * This file is provided under a dual BSD/GPLv2 license. When using or
30 * redistributing this file, you may do so under either license.
34 * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
36 * This program is free software; you can redistribute it and/or modify
37 * it under the terms of version 2 of the GNU General Public License as
38 * published by the Free Software Foundation.
40 * This program is distributed in the hope that it will be useful, but
41 * WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43 * General Public License for more details.
45 * You should have received a copy of the GNU General Public License
46 * along with this program; if not, write to the Free Software
47 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
50 * The full GNU General Public License is included in this distribution
51 * in the file called COPYING.
53 * Contact Information:
54 * Intel Linux Wireless <ilw@linux.intel.com>
55 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
60 * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
61 * All rights reserved.
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
67 * * Redistributions of source code must retain the above copyright
68 * notice, this list of conditions and the following disclaimer.
69 * * Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in
71 * the documentation and/or other materials provided with the
73 * * Neither the name Intel Corporation nor the names of its
74 * contributors may be used to endorse or promote products derived
75 * from this software without specific prior written permission.
77 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
78 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
79 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
80 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
81 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
82 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
83 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
84 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
85 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
86 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
87 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91 * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
93 * Permission to use, copy, modify, and distribute this software for any
94 * purpose with or without fee is hereby granted, provided that the above
95 * copyright notice and this permission notice appear in all copies.
97 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
98 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
99 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
100 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
101 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
102 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
103 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
105 #include <sys/cdefs.h>
106 __FBSDID("$FreeBSD$");
108 #include <sys/param.h>
110 #include <sys/endian.h>
111 #include <sys/firmware.h>
112 #include <sys/kernel.h>
113 #include <sys/malloc.h>
114 #include <sys/mbuf.h>
115 #include <sys/rman.h>
116 #include <sys/sysctl.h>
117 #include <sys/linker.h>
119 #include <machine/endian.h>
121 #include <bus/pci/pcivar.h>
122 #include <bus/pci/pcireg.h>
127 #include <net/if_var.h>
128 #include <net/if_arp.h>
129 #include <net/if_dl.h>
130 #include <net/if_media.h>
131 #include <net/if_types.h>
133 #include <netinet/in.h>
134 #include <netinet/in_systm.h>
135 #include <netinet/if_ether.h>
136 #include <netinet/ip.h>
138 #include <netproto/802_11/ieee80211_var.h>
139 #include <netproto/802_11/ieee80211_regdomain.h>
140 #include <netproto/802_11/ieee80211_ratectl.h>
141 #include <netproto/802_11/ieee80211_radiotap.h>
143 #include "if_iwmreg.h"
144 #include "if_iwmvar.h"
145 #include "if_iwm_debug.h"
146 #include "if_iwm_notif_wait.h"
147 #include "if_iwm_util.h"
148 #include "if_iwm_scan.h"
150 #define IWM_DENSE_EBS_SCAN_RATIO 5
151 #define IWM_SPARSE_EBS_SCAN_RATIO 1
154 iwm_mvm_scan_rx_chain(struct iwm_softc
*sc
)
159 rx_ant
= iwm_mvm_get_valid_rx_ant(sc
);
160 rx_chain
= rx_ant
<< IWM_PHY_RX_CHAIN_VALID_POS
;
161 rx_chain
|= rx_ant
<< IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS
;
162 rx_chain
|= rx_ant
<< IWM_PHY_RX_CHAIN_FORCE_SEL_POS
;
163 rx_chain
|= 0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS
;
164 return htole16(rx_chain
);
168 iwm_mvm_scan_rate_n_flags(struct iwm_softc
*sc
, int flags
, int no_cck
)
173 for (i
= 0, ind
= sc
->sc_scan_last_antenna
;
174 i
< IWM_RATE_MCS_ANT_NUM
; i
++) {
175 ind
= (ind
+ 1) % IWM_RATE_MCS_ANT_NUM
;
176 if (iwm_mvm_get_valid_tx_ant(sc
) & (1 << ind
)) {
177 sc
->sc_scan_last_antenna
= ind
;
181 tx_ant
= (1 << sc
->sc_scan_last_antenna
) << IWM_RATE_MCS_ANT_POS
;
183 if ((flags
& IEEE80211_CHAN_2GHZ
) && !no_cck
)
184 return htole32(IWM_RATE_1M_PLCP
| IWM_RATE_MCS_CCK_MSK
|
187 return htole32(IWM_RATE_6M_PLCP
| tx_ant
);
192 iwm_mvm_ebs_status_str(enum iwm_scan_ebs_status status
)
195 case IWM_SCAN_EBS_SUCCESS
:
197 case IWM_SCAN_EBS_INACTIVE
:
199 case IWM_SCAN_EBS_FAILED
:
200 case IWM_SCAN_EBS_CHAN_NOT_FOUND
:
208 iwm_mvm_rx_lmac_scan_complete_notif(struct iwm_softc
*sc
,
209 struct iwm_rx_packet
*pkt
)
211 struct iwm_periodic_scan_complete
*scan_notif
= (void *)pkt
->data
;
213 boolean_t aborted
= (scan_notif
->status
== IWM_SCAN_OFFLOAD_ABORTED
);
216 /* If this happens, the firmware has mistakenly sent an LMAC
217 * notification during UMAC scans -- warn and ignore it.
219 if (fw_has_capa(&sc
->ucode_capa
, IWM_UCODE_TLV_CAPA_UMAC_SCAN
)) {
220 device_printf(sc
->sc_dev
,
221 "%s: Mistakenly got LMAC notification during UMAC scan\n",
226 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Regular scan %s, EBS status %s (FW)\n",
227 aborted
? "aborted" : "completed",
228 iwm_mvm_ebs_status_str(scan_notif
->ebs_status
));
230 sc
->last_ebs_successful
=
231 scan_notif
->ebs_status
== IWM_SCAN_EBS_SUCCESS
||
232 scan_notif
->ebs_status
== IWM_SCAN_EBS_INACTIVE
;
237 iwm_mvm_rx_umac_scan_complete_notif(struct iwm_softc
*sc
,
238 struct iwm_rx_packet
*pkt
)
240 struct iwm_umac_scan_complete
*notif
= (void *)pkt
->data
;
242 uint32_t uid
= le32toh(notif
->uid
);
243 boolean_t aborted
= (notif
->status
== IWM_SCAN_OFFLOAD_ABORTED
);
246 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
247 "Scan completed, uid %u, status %s, EBS status %s\n",
249 aborted
? "aborted" : "completed",
250 iwm_mvm_ebs_status_str(notif
->ebs_status
));
252 if (notif
->ebs_status
!= IWM_SCAN_EBS_SUCCESS
&&
253 notif
->ebs_status
!= IWM_SCAN_EBS_INACTIVE
)
254 sc
->last_ebs_successful
= FALSE
;
258 iwm_mvm_scan_skip_channel(struct ieee80211_channel
*c
)
260 if (IEEE80211_IS_CHAN_2GHZ(c
) && IEEE80211_IS_CHAN_B(c
))
262 else if (IEEE80211_IS_CHAN_5GHZ(c
) && IEEE80211_IS_CHAN_A(c
))
269 iwm_mvm_lmac_scan_fill_channels(struct iwm_softc
*sc
,
270 struct iwm_scan_channel_cfg_lmac
*chan
, int n_ssids
)
272 struct ieee80211com
*ic
= &sc
->sc_ic
;
273 struct ieee80211_channel
*c
;
278 j
< ic
->ic_nchans
&& nchan
< sc
->ucode_capa
.n_scan_channels
; j
++) {
279 c
= &ic
->ic_channels
[j
];
280 /* For 2GHz, only populate 11b channels */
281 /* For 5GHz, only populate 11a channels */
283 * Catch other channels, in case we have 900MHz channels or
284 * something in the chanlist.
286 if (iwm_mvm_scan_skip_channel(c
)) {
287 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
288 "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
289 __func__
, c
->ic_freq
, c
->ic_ieee
, c
->ic_flags
);
293 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
294 "Adding channel %d (%d Mhz) to the list\n",
296 chan
->channel_num
= htole16(ieee80211_mhz2ieee(c
->ic_freq
, 0));
297 chan
->iter_count
= htole16(1);
298 chan
->iter_interval
= htole32(0);
299 chan
->flags
= htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL
);
300 #if 0 /* makes scanning while associated less useful */
302 chan
->flags
|= htole32(1 << 1); /* select SSID 0 */
312 iwm_mvm_umac_scan_fill_channels(struct iwm_softc
*sc
,
313 struct iwm_scan_channel_cfg_umac
*chan
, int n_ssids
)
315 struct ieee80211com
*ic
= &sc
->sc_ic
;
316 struct ieee80211_channel
*c
;
321 j
< ic
->ic_nchans
&& nchan
< sc
->ucode_capa
.n_scan_channels
; j
++) {
322 c
= &ic
->ic_channels
[j
];
323 /* For 2GHz, only populate 11b channels */
324 /* For 5GHz, only populate 11a channels */
326 * Catch other channels, in case we have 900MHz channels or
327 * something in the chanlist.
329 if (iwm_mvm_scan_skip_channel(c
)) {
330 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
331 "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
332 __func__
, c
->ic_freq
, c
->ic_ieee
, c
->ic_flags
);
336 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
337 "Adding channel %d (%d Mhz) to the list\n",
339 chan
->channel_num
= ieee80211_mhz2ieee(c
->ic_freq
, 0);
340 chan
->iter_count
= 1;
341 chan
->iter_interval
= htole16(0);
342 chan
->flags
= htole32(0);
343 #if 0 /* makes scanning while associated less useful */
345 chan
->flags
= htole32(1 << 0); /* select SSID 0 */
355 iwm_mvm_fill_probe_req(struct iwm_softc
*sc
, struct iwm_scan_probe_req
*preq
)
357 struct ieee80211com
*ic
= &sc
->sc_ic
;
358 struct ieee80211vap
*vap
= TAILQ_FIRST(&ic
->ic_vaps
);
359 struct ieee80211_frame
*wh
= (struct ieee80211_frame
*)preq
->buf
;
360 struct ieee80211_rateset
*rs
;
361 size_t remain
= sizeof(preq
->buf
);
364 const uint8_t *ssid
= NULL
;
366 memset(preq
, 0, sizeof(*preq
));
368 /* Ensure enough space for header and SSID IE. */
369 if (remain
< sizeof(*wh
) + 2 + ssid_len
)
373 * Build a probe request frame. Most of the following code is a
374 * copy & paste of what is done in net80211.
376 wh
->i_fc
[0] = IEEE80211_FC0_VERSION_0
| IEEE80211_FC0_TYPE_MGT
|
377 IEEE80211_FC0_SUBTYPE_PROBE_REQ
;
378 wh
->i_fc
[1] = IEEE80211_FC1_DIR_NODS
;
379 IEEE80211_ADDR_COPY(wh
->i_addr1
, ieee80211broadcastaddr
);
380 IEEE80211_ADDR_COPY(wh
->i_addr2
, vap
? vap
->iv_myaddr
: ic
->ic_macaddr
);
381 IEEE80211_ADDR_COPY(wh
->i_addr3
, ieee80211broadcastaddr
);
382 *(uint16_t *)&wh
->i_dur
[0] = 0; /* filled by HW */
383 *(uint16_t *)&wh
->i_seq
[0] = 0; /* filled by HW */
385 frm
= (uint8_t *)(wh
+ 1);
386 frm
= ieee80211_add_ssid(frm
, ssid
, ssid_len
);
388 /* Tell the firmware where the MAC header is. */
389 preq
->mac_header
.offset
= 0;
390 preq
->mac_header
.len
= htole16(frm
- (uint8_t *)wh
);
391 remain
-= frm
- (uint8_t *)wh
;
393 /* Fill in 2GHz IEs and tell firmware where they are. */
394 rs
= &ic
->ic_sup_rates
[IEEE80211_MODE_11G
];
395 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
) {
396 if (remain
< 4 + rs
->rs_nrates
)
398 } else if (remain
< 2 + rs
->rs_nrates
) {
401 preq
->band_data
[0].offset
= htole16(frm
- (uint8_t *)wh
);
403 frm
= ieee80211_add_rates(frm
, rs
);
404 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
)
405 frm
= ieee80211_add_xrates(frm
, rs
);
406 preq
->band_data
[0].len
= htole16(frm
- pos
);
409 if (fw_has_capa(&sc
->ucode_capa
,
410 IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT
)) {
413 *frm
++ = IEEE80211_ELEMID_DSPARMS
;
419 if (sc
->nvm_data
->sku_cap_band_52GHz_enable
) {
420 /* Fill in 5GHz IEs. */
421 rs
= &ic
->ic_sup_rates
[IEEE80211_MODE_11A
];
422 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
) {
423 if (remain
< 4 + rs
->rs_nrates
)
425 } else if (remain
< 2 + rs
->rs_nrates
) {
428 preq
->band_data
[1].offset
= htole16(frm
- (uint8_t *)wh
);
430 frm
= ieee80211_add_rates(frm
, rs
);
431 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
)
432 frm
= ieee80211_add_xrates(frm
, rs
);
433 preq
->band_data
[1].len
= htole16(frm
- pos
);
437 /* Send 11n IEs on both 2GHz and 5GHz bands. */
438 preq
->common_data
.offset
= htole16(frm
- (uint8_t *)wh
);
441 if (ic
->ic_flags
& IEEE80211_F_HTON
) {
444 frm
= ieee80211_add_htcaps(frm
, ic
);
445 /* XXX add WME info? */
448 preq
->common_data
.len
= htole16(frm
- pos
);
454 iwm_mvm_config_umac_scan(struct iwm_softc
*sc
)
456 struct ieee80211com
*ic
= &sc
->sc_ic
;
457 struct ieee80211vap
*vap
= TAILQ_FIRST(&ic
->ic_vaps
);
459 struct iwm_scan_config
*scan_config
;
462 struct ieee80211_channel
*c
;
463 struct iwm_host_cmd hcmd
= {
464 .id
= iwm_cmd_id(IWM_SCAN_CFG_CMD
, IWM_ALWAYS_LONG_GROUP
, 0),
465 .flags
= IWM_CMD_SYNC
,
467 static const uint32_t rates
= (IWM_SCAN_CONFIG_RATE_1M
|
468 IWM_SCAN_CONFIG_RATE_2M
| IWM_SCAN_CONFIG_RATE_5M
|
469 IWM_SCAN_CONFIG_RATE_11M
| IWM_SCAN_CONFIG_RATE_6M
|
470 IWM_SCAN_CONFIG_RATE_9M
| IWM_SCAN_CONFIG_RATE_12M
|
471 IWM_SCAN_CONFIG_RATE_18M
| IWM_SCAN_CONFIG_RATE_24M
|
472 IWM_SCAN_CONFIG_RATE_36M
| IWM_SCAN_CONFIG_RATE_48M
|
473 IWM_SCAN_CONFIG_RATE_54M
);
475 cmd_size
= sizeof(*scan_config
) + sc
->ucode_capa
.n_scan_channels
;
477 scan_config
= kmalloc(cmd_size
, M_DEVBUF
, M_INTWAIT
| M_ZERO
);
478 if (scan_config
== NULL
)
481 scan_config
->tx_chains
= htole32(iwm_mvm_get_valid_tx_ant(sc
));
482 scan_config
->rx_chains
= htole32(iwm_mvm_get_valid_rx_ant(sc
));
483 scan_config
->legacy_rates
= htole32(rates
|
484 IWM_SCAN_CONFIG_SUPPORTED_RATE(rates
));
486 /* These timings correspond to iwlwifi's UNASSOC scan. */
487 scan_config
->dwell_active
= 10;
488 scan_config
->dwell_passive
= 110;
489 scan_config
->dwell_fragmented
= 44;
490 scan_config
->dwell_extended
= 90;
491 scan_config
->out_of_channel_time
= htole32(0);
492 scan_config
->suspend_time
= htole32(0);
494 IEEE80211_ADDR_COPY(scan_config
->mac_addr
,
495 vap
? vap
->iv_myaddr
: ic
->ic_macaddr
);
497 scan_config
->bcast_sta_id
= sc
->sc_aux_sta
.sta_id
;
498 scan_config
->channel_flags
= IWM_CHANNEL_FLAG_EBS
|
499 IWM_CHANNEL_FLAG_ACCURATE_EBS
| IWM_CHANNEL_FLAG_EBS_ADD
|
500 IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE
;
503 j
< ic
->ic_nchans
&& nchan
< sc
->ucode_capa
.n_scan_channels
; j
++) {
504 c
= &ic
->ic_channels
[j
];
505 /* For 2GHz, only populate 11b channels */
506 /* For 5GHz, only populate 11a channels */
508 * Catch other channels, in case we have 900MHz channels or
509 * something in the chanlist.
511 if (iwm_mvm_scan_skip_channel(c
))
513 scan_config
->channel_array
[nchan
++] =
514 ieee80211_mhz2ieee(c
->ic_freq
, 0);
517 scan_config
->flags
= htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE
|
518 IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS
|
519 IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS
|
520 IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS
|
521 IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID
|
522 IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES
|
523 IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES
|
524 IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR
|
525 IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS
|
526 IWM_SCAN_CONFIG_N_CHANNELS(nchan
) |
527 IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED
);
529 hcmd
.data
[0] = scan_config
;
530 hcmd
.len
[0] = cmd_size
;
532 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Sending UMAC scan config\n");
534 ret
= iwm_send_cmd(sc
, &hcmd
);
536 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
537 "UMAC scan config was sent successfully\n");
539 kfree(scan_config
, M_DEVBUF
);
544 iwm_mvm_scan_use_ebs(struct iwm_softc
*sc
)
546 const struct iwm_ucode_capabilities
*capa
= &sc
->ucode_capa
;
548 /* We can only use EBS if:
549 * 1. the feature is supported;
550 * 2. the last EBS was successful;
551 * 3. if only single scan, the single scan EBS API is supported;
552 * 4. it's not a p2p find operation.
554 return ((capa
->flags
& IWM_UCODE_TLV_FLAGS_EBS_SUPPORT
) &&
555 sc
->last_ebs_successful
);
559 iwm_mvm_umac_scan(struct iwm_softc
*sc
)
561 struct iwm_host_cmd hcmd
= {
562 .id
= iwm_cmd_id(IWM_SCAN_REQ_UMAC
, IWM_ALWAYS_LONG_GROUP
, 0),
565 .flags
= IWM_CMD_SYNC
,
567 struct iwm_scan_req_umac
*req
;
568 struct iwm_scan_req_umac_tail
*tail
;
571 const uint8_t *ssid
= NULL
;
574 req_len
= sizeof(struct iwm_scan_req_umac
) +
575 (sizeof(struct iwm_scan_channel_cfg_umac
) *
576 sc
->ucode_capa
.n_scan_channels
) +
577 sizeof(struct iwm_scan_req_umac_tail
);
578 if (req_len
> IWM_MAX_CMD_PAYLOAD_SIZE
)
580 req
= kmalloc(req_len
, M_DEVBUF
, M_INTWAIT
| M_ZERO
);
584 hcmd
.len
[0] = (uint16_t)req_len
;
585 hcmd
.data
[0] = (void *)req
;
587 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Handling ieee80211 scan request\n");
589 /* These timings correspond to iwlwifi's UNASSOC scan. */
590 req
->active_dwell
= 10;
591 req
->passive_dwell
= 110;
592 req
->fragmented_dwell
= 44;
593 req
->extended_dwell
= 90;
594 req
->max_out_time
= 0;
595 req
->suspend_time
= 0;
597 req
->scan_priority
= htole32(IWM_SCAN_PRIORITY_HIGH
);
598 req
->ooc_priority
= htole32(IWM_SCAN_PRIORITY_HIGH
);
600 req
->n_channels
= iwm_mvm_umac_scan_fill_channels(sc
,
601 (struct iwm_scan_channel_cfg_umac
*)req
->data
, ssid_len
!= 0);
603 req
->general_flags
= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL
|
604 IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE
|
605 IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL
);
607 tail
= (void *)((char *)&req
->data
+
608 sizeof(struct iwm_scan_channel_cfg_umac
) *
609 sc
->ucode_capa
.n_scan_channels
);
611 /* Check if we're doing an active directed scan. */
613 tail
->direct_scan
[0].id
= IEEE80211_ELEMID_SSID
;
614 tail
->direct_scan
[0].len
= ssid_len
;
615 memcpy(tail
->direct_scan
[0].ssid
, ssid
, ssid_len
);
616 req
->general_flags
|=
617 htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT
);
619 req
->general_flags
|= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE
);
622 if (iwm_mvm_scan_use_ebs(sc
))
623 req
->channel_flags
= IWM_SCAN_CHANNEL_FLAG_EBS
|
624 IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE
|
625 IWM_SCAN_CHANNEL_FLAG_CACHE_ADD
;
627 if (fw_has_capa(&sc
->ucode_capa
,
628 IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT
))
629 req
->general_flags
|=
630 htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED
);
632 ret
= iwm_mvm_fill_probe_req(sc
, &tail
->preq
);
634 kfree(req
, M_DEVBUF
);
638 /* Specify the scan plan: We'll do one iteration. */
639 tail
->schedule
[0].interval
= 0;
640 tail
->schedule
[0].iter_count
= 1;
642 ret
= iwm_send_cmd(sc
, &hcmd
);
644 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
645 "Scan request was sent successfully\n");
646 kfree(req
, M_DEVBUF
);
651 iwm_mvm_lmac_scan(struct iwm_softc
*sc
)
653 struct iwm_host_cmd hcmd
= {
654 .id
= IWM_SCAN_OFFLOAD_REQUEST_CMD
,
657 .flags
= IWM_CMD_SYNC
,
659 struct iwm_scan_req_lmac
*req
;
663 const uint8_t *ssid
= NULL
;
665 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
666 "Handling ieee80211 scan request\n");
668 req_len
= sizeof(struct iwm_scan_req_lmac
) +
669 (sizeof(struct iwm_scan_channel_cfg_lmac
) *
670 sc
->ucode_capa
.n_scan_channels
) + sizeof(struct iwm_scan_probe_req
);
671 if (req_len
> IWM_MAX_CMD_PAYLOAD_SIZE
)
673 req
= kmalloc(req_len
, M_DEVBUF
, M_INTWAIT
| M_ZERO
);
677 hcmd
.len
[0] = (uint16_t)req_len
;
678 hcmd
.data
[0] = (void *)req
;
680 /* These timings correspond to iwlwifi's UNASSOC scan. */
681 req
->active_dwell
= 10;
682 req
->passive_dwell
= 110;
683 req
->fragmented_dwell
= 44;
684 req
->extended_dwell
= 90;
685 req
->max_out_time
= 0;
686 req
->suspend_time
= 0;
688 req
->scan_prio
= htole32(IWM_SCAN_PRIORITY_HIGH
);
689 req
->rx_chain_select
= iwm_mvm_scan_rx_chain(sc
);
690 req
->iter_num
= htole32(1);
693 req
->scan_flags
= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL
|
694 IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE
|
695 IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL
);
697 req
->scan_flags
|= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASSIVE
);
700 htole32(IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION
);
701 if (fw_has_capa(&sc
->ucode_capa
,
702 IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT
))
703 req
->scan_flags
|= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED
);
705 req
->flags
= htole32(IWM_PHY_BAND_24
);
706 if (sc
->nvm_data
->sku_cap_band_52GHz_enable
)
707 req
->flags
|= htole32(IWM_PHY_BAND_5
);
709 htole32(IWM_MAC_FILTER_ACCEPT_GRP
| IWM_MAC_FILTER_IN_BEACON
);
711 /* Tx flags 2 GHz. */
712 req
->tx_cmd
[0].tx_flags
= htole32(IWM_TX_CMD_FLG_SEQ_CTL
|
713 IWM_TX_CMD_FLG_BT_DIS
);
714 req
->tx_cmd
[0].rate_n_flags
=
715 iwm_mvm_scan_rate_n_flags(sc
, IEEE80211_CHAN_2GHZ
, 1/*XXX*/);
716 req
->tx_cmd
[0].sta_id
= sc
->sc_aux_sta
.sta_id
;
718 /* Tx flags 5 GHz. */
719 req
->tx_cmd
[1].tx_flags
= htole32(IWM_TX_CMD_FLG_SEQ_CTL
|
720 IWM_TX_CMD_FLG_BT_DIS
);
721 req
->tx_cmd
[1].rate_n_flags
=
722 iwm_mvm_scan_rate_n_flags(sc
, IEEE80211_CHAN_5GHZ
, 1/*XXX*/);
723 req
->tx_cmd
[1].sta_id
= sc
->sc_aux_sta
.sta_id
;
725 /* Check if we're doing an active directed scan. */
727 req
->direct_scan
[0].id
= IEEE80211_ELEMID_SSID
;
728 req
->direct_scan
[0].len
= ssid_len
;
729 memcpy(req
->direct_scan
[0].ssid
, ssid
, ssid_len
);
732 req
->n_channels
= iwm_mvm_lmac_scan_fill_channels(sc
,
733 (struct iwm_scan_channel_cfg_lmac
*)req
->data
,
736 ret
= iwm_mvm_fill_probe_req(sc
,
737 (struct iwm_scan_probe_req
*)(req
->data
+
738 (sizeof(struct iwm_scan_channel_cfg_lmac
) *
739 sc
->ucode_capa
.n_scan_channels
)));
741 kfree(req
, M_DEVBUF
);
745 /* Specify the scan plan: We'll do one iteration. */
746 req
->schedule
[0].iterations
= 1;
747 req
->schedule
[0].full_scan_mul
= 1;
749 if (iwm_mvm_scan_use_ebs(sc
)) {
750 req
->channel_opt
[0].flags
=
751 htole16(IWM_SCAN_CHANNEL_FLAG_EBS
|
752 IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE
|
753 IWM_SCAN_CHANNEL_FLAG_CACHE_ADD
);
754 req
->channel_opt
[0].non_ebs_ratio
=
755 htole16(IWM_DENSE_EBS_SCAN_RATIO
);
756 req
->channel_opt
[1].flags
=
757 htole16(IWM_SCAN_CHANNEL_FLAG_EBS
|
758 IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE
|
759 IWM_SCAN_CHANNEL_FLAG_CACHE_ADD
);
760 req
->channel_opt
[1].non_ebs_ratio
=
761 htole16(IWM_SPARSE_EBS_SCAN_RATIO
);
764 ret
= iwm_send_cmd(sc
, &hcmd
);
766 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
767 "Scan request was sent successfully\n");
769 kfree(req
, M_DEVBUF
);
774 iwm_mvm_lmac_scan_abort(struct iwm_softc
*sc
)
777 struct iwm_host_cmd hcmd
= {
778 .id
= IWM_SCAN_OFFLOAD_ABORT_CMD
,
781 .flags
= IWM_CMD_SYNC
,
785 ret
= iwm_mvm_send_cmd_status(sc
, &hcmd
, &status
);
789 if (status
!= IWM_CAN_ABORT_STATUS
) {
791 * The scan abort will return 1 for success or
792 * 2 for "failure". A failure condition can be
793 * due to simply not being in an active scan which
794 * can occur if we send the scan abort before the
795 * microcode has notified us that a scan is completed.
797 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
798 "SCAN OFFLOAD ABORT ret %d.\n", status
);
806 iwm_mvm_umac_scan_abort(struct iwm_softc
*sc
)
808 struct iwm_umac_scan_abort cmd
= {};
812 cmd
.uid
= htole32(uid
);
814 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Sending scan abort, uid %u\n", uid
);
816 ret
= iwm_mvm_send_cmd_pdu(sc
,
817 iwm_cmd_id(IWM_SCAN_ABORT_UMAC
,
818 IWM_ALWAYS_LONG_GROUP
, 0),
819 0, sizeof(cmd
), &cmd
);
825 iwm_mvm_scan_stop_wait(struct iwm_softc
*sc
)
827 struct iwm_notification_wait wait_scan_done
;
828 static const uint16_t scan_done_notif
[] = { IWM_SCAN_COMPLETE_UMAC
,
829 IWM_SCAN_OFFLOAD_COMPLETE
, };
832 iwm_init_notification_wait(sc
->sc_notif_wait
, &wait_scan_done
,
833 scan_done_notif
, NELEM(scan_done_notif
),
836 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Preparing to stop scan\n");
838 if (fw_has_capa(&sc
->ucode_capa
, IWM_UCODE_TLV_CAPA_UMAC_SCAN
))
839 ret
= iwm_mvm_umac_scan_abort(sc
);
841 ret
= iwm_mvm_lmac_scan_abort(sc
);
844 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "couldn't stop scan\n");
845 iwm_remove_notification(sc
->sc_notif_wait
, &wait_scan_done
);
850 ret
= iwm_wait_notification(sc
->sc_notif_wait
, &wait_scan_done
, hz
);