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/param.h>
107 #include <sys/conf.h>
108 #include <sys/endian.h>
109 #include <sys/firmware.h>
110 #include <sys/kernel.h>
111 #include <sys/malloc.h>
112 #include <sys/mbuf.h>
113 #include <sys/rman.h>
114 #include <sys/sysctl.h>
115 #include <sys/linker.h>
117 #include <machine/endian.h>
119 #include <bus/pci/pcivar.h>
120 #include <bus/pci/pcireg.h>
125 #include <net/if_var.h>
126 #include <net/if_arp.h>
127 #include <net/if_dl.h>
128 #include <net/if_media.h>
129 #include <net/if_types.h>
131 #include <netinet/in.h>
132 #include <netinet/in_systm.h>
133 #include <netinet/if_ether.h>
134 #include <netinet/ip.h>
136 #include <netproto/802_11/ieee80211_var.h>
137 #include <netproto/802_11/ieee80211_regdomain.h>
138 #include <netproto/802_11/ieee80211_ratectl.h>
139 #include <netproto/802_11/ieee80211_radiotap.h>
141 #include "if_iwmreg.h"
142 #include "if_iwmvar.h"
143 #include "if_iwm_debug.h"
144 #include "if_iwm_notif_wait.h"
145 #include "if_iwm_util.h"
146 #include "if_iwm_scan.h"
152 #define IWM_DENSE_EBS_SCAN_RATIO 5
153 #define IWM_SPARSE_EBS_SCAN_RATIO 1
156 iwm_scan_rx_chain(struct iwm_softc
*sc
)
161 rx_ant
= iwm_get_valid_rx_ant(sc
);
162 rx_chain
= rx_ant
<< IWM_PHY_RX_CHAIN_VALID_POS
;
163 rx_chain
|= rx_ant
<< IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS
;
164 rx_chain
|= rx_ant
<< IWM_PHY_RX_CHAIN_FORCE_SEL_POS
;
165 rx_chain
|= 0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS
;
166 return htole16(rx_chain
);
170 iwm_scan_rxon_flags(struct ieee80211_channel
*c
)
172 if (IEEE80211_IS_CHAN_2GHZ(c
))
173 return htole32(IWM_PHY_BAND_24
);
175 return htole32(IWM_PHY_BAND_5
);
179 iwm_scan_rate_n_flags(struct iwm_softc
*sc
, int flags
, int no_cck
)
184 for (i
= 0, ind
= sc
->sc_scan_last_antenna
;
185 i
< IWM_RATE_MCS_ANT_NUM
; i
++) {
186 ind
= (ind
+ 1) % IWM_RATE_MCS_ANT_NUM
;
187 if (iwm_get_valid_tx_ant(sc
) & (1 << ind
)) {
188 sc
->sc_scan_last_antenna
= ind
;
192 tx_ant
= (1 << sc
->sc_scan_last_antenna
) << IWM_RATE_MCS_ANT_POS
;
194 if ((flags
& IEEE80211_CHAN_2GHZ
) && !no_cck
)
195 return htole32(IWM_RATE_1M_PLCP
| IWM_RATE_MCS_CCK_MSK
|
198 return htole32(IWM_RATE_6M_PLCP
| tx_ant
);
201 static inline boolean_t
202 iwm_rrm_scan_needed(struct iwm_softc
*sc
)
204 /* require rrm scan whenever the fw supports it */
205 return iwm_fw_has_capa(sc
, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT
);
210 iwm_ebs_status_str(enum iwm_scan_ebs_status status
)
213 case IWM_SCAN_EBS_SUCCESS
:
215 case IWM_SCAN_EBS_INACTIVE
:
217 case IWM_SCAN_EBS_FAILED
:
218 case IWM_SCAN_EBS_CHAN_NOT_FOUND
:
225 iwm_offload_status_str(enum iwm_scan_offload_complete_status status
)
227 return (status
== IWM_SCAN_OFFLOAD_ABORTED
) ? "aborted" : "completed";
232 iwm_rx_lmac_scan_complete_notif(struct iwm_softc
*sc
,
233 struct iwm_rx_packet
*pkt
)
235 struct iwm_periodic_scan_complete
*scan_notif
= (void *)pkt
->data
;
237 /* If this happens, the firmware has mistakenly sent an LMAC
238 * notification during UMAC scans -- warn and ignore it.
240 if (iwm_fw_has_capa(sc
, IWM_UCODE_TLV_CAPA_UMAC_SCAN
)) {
241 device_printf(sc
->sc_dev
,
242 "%s: Mistakenly got LMAC notification during UMAC scan\n",
247 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Regular scan %s, EBS status %s (FW)\n",
248 iwm_offload_status_str(scan_notif
->status
),
249 iwm_ebs_status_str(scan_notif
->ebs_status
));
251 sc
->last_ebs_successful
=
252 scan_notif
->ebs_status
== IWM_SCAN_EBS_SUCCESS
||
253 scan_notif
->ebs_status
== IWM_SCAN_EBS_INACTIVE
;
258 iwm_rx_umac_scan_complete_notif(struct iwm_softc
*sc
,
259 struct iwm_rx_packet
*pkt
)
261 struct iwm_umac_scan_complete
*notif
= (void *)pkt
->data
;
263 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
264 "Scan completed, uid %u, status %s, EBS status %s\n",
266 iwm_offload_status_str(notif
->status
),
267 iwm_ebs_status_str(notif
->ebs_status
));
269 if (notif
->ebs_status
!= IWM_SCAN_EBS_SUCCESS
&&
270 notif
->ebs_status
!= IWM_SCAN_EBS_INACTIVE
)
271 sc
->last_ebs_successful
= FALSE
;
275 iwm_scan_skip_channel(struct ieee80211_channel
*c
)
277 if (IEEE80211_IS_CHAN_2GHZ(c
) && IEEE80211_IS_CHAN_B(c
))
279 else if (IEEE80211_IS_CHAN_5GHZ(c
) && IEEE80211_IS_CHAN_A(c
))
286 iwm_lmac_scan_fill_channels(struct iwm_softc
*sc
,
287 struct iwm_scan_channel_cfg_lmac
*chan
, int n_ssids
)
289 struct ieee80211com
*ic
= &sc
->sc_ic
;
290 struct ieee80211_scan_state
*ss
= ic
->ic_scan
;
291 struct ieee80211_channel
*c
;
296 j
< ss
->ss_last
&& nchan
< sc
->sc_fw
.ucode_capa
.n_scan_channels
;
300 * Catch other channels, in case we have 900MHz channels or
301 * something in the chanlist.
303 if (!IEEE80211_IS_CHAN_2GHZ(c
) && !IEEE80211_IS_CHAN_5GHZ(c
)) {
304 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
305 "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
306 __func__
, c
->ic_freq
, c
->ic_ieee
, c
->ic_flags
);
310 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
311 "Adding channel %d (%d Mhz) to the list\n",
313 chan
->channel_num
= htole16(ieee80211_mhz2ieee(c
->ic_freq
, 0));
314 chan
->iter_count
= htole16(1);
315 chan
->iter_interval
= htole32(0);
316 chan
->flags
= htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL
);
317 chan
->flags
|= htole32(IWM_SCAN_CHANNEL_NSSIDS(n_ssids
));
318 /* XXX IEEE80211_SCAN_NOBCAST flag is never set. */
319 if (!IEEE80211_IS_CHAN_PASSIVE(c
) &&
320 (!(ss
->ss_flags
& IEEE80211_SCAN_NOBCAST
) || n_ssids
!= 0))
321 chan
->flags
|= htole32(IWM_SCAN_CHANNEL_TYPE_ACTIVE
);
330 iwm_umac_scan_fill_channels(struct iwm_softc
*sc
,
331 struct iwm_scan_channel_cfg_umac
*chan
, int n_ssids
)
333 struct ieee80211com
*ic
= &sc
->sc_ic
;
334 struct ieee80211_scan_state
*ss
= ic
->ic_scan
;
335 struct ieee80211_channel
*c
;
340 j
< ss
->ss_last
&& nchan
< sc
->sc_fw
.ucode_capa
.n_scan_channels
;
344 * Catch other channels, in case we have 900MHz channels or
345 * something in the chanlist.
347 if (!IEEE80211_IS_CHAN_2GHZ(c
) && !IEEE80211_IS_CHAN_5GHZ(c
)) {
348 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
349 "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
350 __func__
, c
->ic_freq
, c
->ic_ieee
, c
->ic_flags
);
354 IWM_DPRINTF(sc
, IWM_DEBUG_RESET
| IWM_DEBUG_EEPROM
,
355 "Adding channel %d (%d Mhz) to the list\n",
357 chan
->channel_num
= ieee80211_mhz2ieee(c
->ic_freq
, 0);
358 chan
->iter_count
= 1;
359 chan
->iter_interval
= htole16(0);
360 chan
->flags
= htole32(IWM_SCAN_CHANNEL_UMAC_NSSIDS(n_ssids
));
369 iwm_fill_probe_req(struct iwm_softc
*sc
, struct iwm_scan_probe_req_v1
*preq
)
371 struct ieee80211com
*ic
= &sc
->sc_ic
;
372 struct ieee80211vap
*vap
= TAILQ_FIRST(&ic
->ic_vaps
);
373 struct ieee80211_frame
*wh
= (struct ieee80211_frame
*)preq
->buf
;
374 struct ieee80211_rateset
*rs
;
375 size_t remain
= sizeof(preq
->buf
);
378 memset(preq
, 0, sizeof(*preq
));
380 /* Ensure enough space for header and SSID IE. */
381 if (remain
< sizeof(*wh
) + 2)
385 * Build a probe request frame. Most of the following code is a
386 * copy & paste of what is done in net80211.
388 wh
->i_fc
[0] = IEEE80211_FC0_VERSION_0
| IEEE80211_FC0_TYPE_MGT
|
389 IEEE80211_FC0_SUBTYPE_PROBE_REQ
;
390 wh
->i_fc
[1] = IEEE80211_FC1_DIR_NODS
;
391 IEEE80211_ADDR_COPY(wh
->i_addr1
, ieee80211broadcastaddr
);
392 IEEE80211_ADDR_COPY(wh
->i_addr2
, vap
? vap
->iv_myaddr
: ic
->ic_macaddr
);
393 IEEE80211_ADDR_COPY(wh
->i_addr3
, ieee80211broadcastaddr
);
394 *(uint16_t *)&wh
->i_dur
[0] = 0; /* filled by HW */
395 *(uint16_t *)&wh
->i_seq
[0] = 0; /* filled by HW */
397 frm
= (uint8_t *)(wh
+ 1);
398 frm
= ieee80211_add_ssid(frm
, NULL
, 0);
400 /* Tell the firmware where the MAC header is. */
401 preq
->mac_header
.offset
= 0;
402 preq
->mac_header
.len
= htole16(frm
- (uint8_t *)wh
);
403 remain
-= frm
- (uint8_t *)wh
;
405 /* Fill in 2GHz IEs and tell firmware where they are. */
406 rs
= &ic
->ic_sup_rates
[IEEE80211_MODE_11G
];
407 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
) {
408 if (remain
< 4 + rs
->rs_nrates
)
410 } else if (remain
< 2 + rs
->rs_nrates
) {
413 preq
->band_data
[0].offset
= htole16(frm
- (uint8_t *)wh
);
415 frm
= ieee80211_add_rates(frm
, rs
);
416 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
)
417 frm
= ieee80211_add_xrates(frm
, rs
);
418 preq
->band_data
[0].len
= htole16(frm
- pos
);
421 if (iwm_rrm_scan_needed(sc
)) {
424 *frm
++ = IEEE80211_ELEMID_DSPARMS
;
430 if (sc
->nvm_data
->sku_cap_band_52GHz_enable
) {
431 /* Fill in 5GHz IEs. */
432 rs
= &ic
->ic_sup_rates
[IEEE80211_MODE_11A
];
433 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
) {
434 if (remain
< 4 + rs
->rs_nrates
)
436 } else if (remain
< 2 + rs
->rs_nrates
) {
439 preq
->band_data
[1].offset
= htole16(frm
- (uint8_t *)wh
);
441 frm
= ieee80211_add_rates(frm
, rs
);
442 if (rs
->rs_nrates
> IEEE80211_RATE_SIZE
)
443 frm
= ieee80211_add_xrates(frm
, rs
);
444 preq
->band_data
[1].len
= htole16(frm
- pos
);
448 /* Send 11n IEs on both 2GHz and 5GHz bands. */
449 preq
->common_data
.offset
= htole16(frm
- (uint8_t *)wh
);
452 if (ic
->ic_flags
& IEEE80211_F_HTON
) {
455 frm
= ieee80211_add_htcaps(frm
, ic
);
456 /* XXX add WME info? */
459 preq
->common_data
.len
= htole16(frm
- pos
);
465 iwm_config_umac_scan(struct iwm_softc
*sc
)
467 struct ieee80211com
*ic
= &sc
->sc_ic
;
468 struct ieee80211vap
*vap
= TAILQ_FIRST(&ic
->ic_vaps
);
470 struct iwm_scan_config
*scan_config
;
473 struct ieee80211_channel
*c
;
474 struct iwm_host_cmd hcmd
= {
475 .id
= iwm_cmd_id(IWM_SCAN_CFG_CMD
, IWM_ALWAYS_LONG_GROUP
, 0),
476 .flags
= IWM_CMD_SYNC
,
478 static const uint32_t rates
= (IWM_SCAN_CONFIG_RATE_1M
|
479 IWM_SCAN_CONFIG_RATE_2M
| IWM_SCAN_CONFIG_RATE_5M
|
480 IWM_SCAN_CONFIG_RATE_11M
| IWM_SCAN_CONFIG_RATE_6M
|
481 IWM_SCAN_CONFIG_RATE_9M
| IWM_SCAN_CONFIG_RATE_12M
|
482 IWM_SCAN_CONFIG_RATE_18M
| IWM_SCAN_CONFIG_RATE_24M
|
483 IWM_SCAN_CONFIG_RATE_36M
| IWM_SCAN_CONFIG_RATE_48M
|
484 IWM_SCAN_CONFIG_RATE_54M
);
486 cmd_size
= sizeof(*scan_config
) + sc
->sc_fw
.ucode_capa
.n_scan_channels
;
488 scan_config
= kmalloc(cmd_size
, M_DEVBUF
, M_WAITOK
| M_ZERO
);
489 if (scan_config
== NULL
)
492 scan_config
->tx_chains
= htole32(iwm_get_valid_tx_ant(sc
));
493 scan_config
->rx_chains
= htole32(iwm_get_valid_rx_ant(sc
));
494 scan_config
->legacy_rates
= htole32(rates
|
495 IWM_SCAN_CONFIG_SUPPORTED_RATE(rates
));
497 /* These timings correspond to iwlwifi's UNASSOC scan. */
498 scan_config
->dwell_active
= 10;
499 scan_config
->dwell_passive
= 110;
500 scan_config
->dwell_fragmented
= 44;
501 scan_config
->dwell_extended
= 90;
502 scan_config
->out_of_channel_time
= htole32(0);
503 scan_config
->suspend_time
= htole32(0);
505 IEEE80211_ADDR_COPY(scan_config
->mac_addr
,
506 vap
? vap
->iv_myaddr
: ic
->ic_macaddr
);
508 scan_config
->bcast_sta_id
= sc
->sc_aux_sta
.sta_id
;
509 scan_config
->channel_flags
= IWM_CHANNEL_FLAG_EBS
|
510 IWM_CHANNEL_FLAG_ACCURATE_EBS
| IWM_CHANNEL_FLAG_EBS_ADD
|
511 IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE
;
514 j
< ic
->ic_nchans
&& nchan
< sc
->sc_fw
.ucode_capa
.n_scan_channels
;
516 c
= &ic
->ic_channels
[j
];
517 /* For 2GHz, only populate 11b channels */
518 /* For 5GHz, only populate 11a channels */
520 * Catch other channels, in case we have 900MHz channels or
521 * something in the chanlist.
523 if (iwm_scan_skip_channel(c
))
525 scan_config
->channel_array
[nchan
++] =
526 ieee80211_mhz2ieee(c
->ic_freq
, 0);
529 scan_config
->flags
= htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE
|
530 IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS
|
531 IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS
|
532 IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS
|
533 IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID
|
534 IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES
|
535 IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES
|
536 IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR
|
537 IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS
|
538 IWM_SCAN_CONFIG_N_CHANNELS(nchan
) |
539 IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED
);
541 hcmd
.data
[0] = scan_config
;
542 hcmd
.len
[0] = cmd_size
;
544 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Sending UMAC scan config\n");
546 ret
= iwm_send_cmd(sc
, &hcmd
);
548 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
549 "UMAC scan config was sent successfully\n");
551 kfree(scan_config
, M_DEVBUF
);
556 iwm_scan_use_ebs(struct iwm_softc
*sc
)
558 const struct iwm_ucode_capabilities
*capa
= &sc
->sc_fw
.ucode_capa
;
560 /* We can only use EBS if:
561 * 1. the feature is supported;
562 * 2. the last EBS was successful;
563 * 3. if only single scan, the single scan EBS API is supported;
564 * 4. it's not a p2p find operation.
566 return ((capa
->flags
& IWM_UCODE_TLV_FLAGS_EBS_SUPPORT
) &&
567 sc
->last_ebs_successful
);
571 iwm_scan_size(struct iwm_softc
*sc
)
575 if (iwm_fw_has_capa(sc
, IWM_UCODE_TLV_CAPA_UMAC_SCAN
)) {
576 if (iwm_fw_has_api(sc
, IWM_UCODE_TLV_API_ADAPTIVE_DWELL
))
577 base_size
= IWM_SCAN_REQ_UMAC_SIZE_V7
;
579 base_size
= IWM_SCAN_REQ_UMAC_SIZE_V1
;
582 sizeof(struct iwm_scan_channel_cfg_umac
) *
583 sc
->sc_fw
.ucode_capa
.n_scan_channels
+
584 sizeof(struct iwm_scan_req_umac_tail_v1
);
586 return sizeof(struct iwm_scan_req_lmac
) +
587 sizeof(struct iwm_scan_channel_cfg_lmac
) *
588 sc
->sc_fw
.ucode_capa
.n_scan_channels
+
589 sizeof(struct iwm_scan_probe_req_v1
);
594 iwm_umac_scan(struct iwm_softc
*sc
)
596 struct iwm_host_cmd hcmd
= {
597 .id
= iwm_cmd_id(IWM_SCAN_REQ_UMAC
, IWM_ALWAYS_LONG_GROUP
, 0),
600 .flags
= IWM_CMD_SYNC
,
602 struct ieee80211_scan_state
*ss
= sc
->sc_ic
.ic_scan
;
603 struct iwm_scan_req_umac
*req
;
604 struct iwm_scan_req_umac_tail_v1
*tail
;
606 uint16_t general_flags
;
607 uint8_t channel_flags
, i
, nssid
;
610 req_len
= iwm_scan_size(sc
);
611 if (req_len
> IWM_MAX_CMD_PAYLOAD_SIZE
)
613 req
= kmalloc(req_len
, M_DEVBUF
, M_WAITOK
| M_ZERO
);
617 hcmd
.len
[0] = (uint16_t)req_len
;
618 hcmd
.data
[0] = (void *)req
;
620 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Handling ieee80211 scan request\n");
622 nssid
= MIN(ss
->ss_nssid
, IWM_PROBE_OPTION_MAX
);
624 general_flags
= IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL
|
625 IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE
;
626 if (!iwm_fw_has_api(sc
, IWM_UCODE_TLV_API_ADAPTIVE_DWELL
))
627 general_flags
|= IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL
;
628 if (iwm_rrm_scan_needed(sc
))
629 general_flags
|= IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED
;
631 general_flags
|= IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT
;
633 general_flags
|= IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE
;
636 if (iwm_scan_use_ebs(sc
))
637 channel_flags
= IWM_SCAN_CHANNEL_FLAG_EBS
|
638 IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE
|
639 IWM_SCAN_CHANNEL_FLAG_CACHE_ADD
;
641 req
->general_flags
= htole16(general_flags
);
642 req
->ooc_priority
= htole32(IWM_SCAN_PRIORITY_HIGH
);
644 /* These timings correspond to iwlwifi's UNASSOC scan. */
645 if (iwm_fw_has_api(sc
, IWM_UCODE_TLV_API_ADAPTIVE_DWELL
)) {
646 req
->v7
.active_dwell
= 10;
647 req
->v7
.passive_dwell
= 110;
648 req
->v7
.fragmented_dwell
= 44;
649 req
->v7
.adwell_default_n_aps_social
= 10;
650 req
->v7
.adwell_default_n_aps
= 2;
651 req
->v7
.adwell_max_budget
= htole16(300);
652 req
->v7
.scan_priority
= htole32(IWM_SCAN_PRIORITY_HIGH
);
653 req
->v7
.channel
.flags
= channel_flags
;
654 req
->v7
.channel
.count
= iwm_umac_scan_fill_channels(sc
,
655 (struct iwm_scan_channel_cfg_umac
*)req
->v7
.data
, nssid
);
657 tail
= (void *)((char *)&req
->v7
.data
+
658 sizeof(struct iwm_scan_channel_cfg_umac
) *
659 sc
->sc_fw
.ucode_capa
.n_scan_channels
);
661 req
->v1
.active_dwell
= 10;
662 req
->v1
.passive_dwell
= 110;
663 req
->v1
.fragmented_dwell
= 44;
664 req
->v1
.extended_dwell
= 90;
665 req
->v1
.scan_priority
= htole32(IWM_SCAN_PRIORITY_HIGH
);
666 req
->v1
.channel
.flags
= channel_flags
;
667 req
->v1
.channel
.count
= iwm_umac_scan_fill_channels(sc
,
668 (struct iwm_scan_channel_cfg_umac
*)req
->v1
.data
, nssid
);
670 tail
= (void *)((char *)&req
->v1
.data
+
671 sizeof(struct iwm_scan_channel_cfg_umac
) *
672 sc
->sc_fw
.ucode_capa
.n_scan_channels
);
675 /* Check if we're doing an active directed scan. */
676 for (i
= 0; i
< nssid
; i
++) {
677 tail
->direct_scan
[i
].id
= IEEE80211_ELEMID_SSID
;
678 tail
->direct_scan
[i
].len
= MIN(ss
->ss_ssid
[i
].len
,
680 memcpy(tail
->direct_scan
[i
].ssid
, ss
->ss_ssid
[i
].ssid
,
681 tail
->direct_scan
[i
].len
);
685 ret
= iwm_fill_probe_req(sc
, &tail
->preq
);
687 kfree(req
, M_DEVBUF
);
691 /* Specify the scan plan: We'll do one iteration. */
692 tail
->schedule
[0].interval
= 0;
693 tail
->schedule
[0].iter_count
= 1;
695 ret
= iwm_send_cmd(sc
, &hcmd
);
697 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
698 "Scan request was sent successfully\n");
699 kfree(req
, M_DEVBUF
);
704 iwm_lmac_scan(struct iwm_softc
*sc
)
706 struct iwm_host_cmd hcmd
= {
707 .id
= IWM_SCAN_OFFLOAD_REQUEST_CMD
,
710 .flags
= IWM_CMD_SYNC
,
712 struct ieee80211_scan_state
*ss
= sc
->sc_ic
.ic_scan
;
713 struct iwm_scan_req_lmac
*req
;
718 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
719 "Handling ieee80211 scan request\n");
721 req_len
= iwm_scan_size(sc
);
722 if (req_len
> IWM_MAX_CMD_PAYLOAD_SIZE
)
724 req
= kmalloc(req_len
, M_DEVBUF
, M_WAITOK
| M_ZERO
);
728 hcmd
.len
[0] = (uint16_t)req_len
;
729 hcmd
.data
[0] = (void *)req
;
731 /* These timings correspond to iwlwifi's UNASSOC scan. */
732 req
->active_dwell
= 10;
733 req
->passive_dwell
= 110;
734 req
->fragmented_dwell
= 44;
735 req
->extended_dwell
= 90;
736 req
->max_out_time
= 0;
737 req
->suspend_time
= 0;
739 req
->scan_prio
= htole32(IWM_SCAN_PRIORITY_HIGH
);
740 req
->rx_chain_select
= iwm_scan_rx_chain(sc
);
741 req
->iter_num
= htole32(1);
744 req
->scan_flags
= htole32(IWM_LMAC_SCAN_FLAG_PASS_ALL
|
745 IWM_LMAC_SCAN_FLAG_ITER_COMPLETE
|
746 IWM_LMAC_SCAN_FLAG_EXTENDED_DWELL
);
747 if (iwm_rrm_scan_needed(sc
))
748 req
->scan_flags
|= htole32(IWM_LMAC_SCAN_FLAGS_RRM_ENABLED
);
750 req
->flags
= iwm_scan_rxon_flags(sc
->sc_ic
.ic_scan
->ss_chans
[0]);
753 htole32(IWM_MAC_FILTER_ACCEPT_GRP
| IWM_MAC_FILTER_IN_BEACON
);
755 /* Tx flags 2 GHz. */
756 req
->tx_cmd
[0].tx_flags
= htole32(IWM_TX_CMD_FLG_SEQ_CTL
|
757 IWM_TX_CMD_FLG_BT_DIS
);
758 req
->tx_cmd
[0].rate_n_flags
=
759 iwm_scan_rate_n_flags(sc
, IEEE80211_CHAN_2GHZ
, 1/*XXX*/);
760 req
->tx_cmd
[0].sta_id
= sc
->sc_aux_sta
.sta_id
;
762 /* Tx flags 5 GHz. */
763 req
->tx_cmd
[1].tx_flags
= htole32(IWM_TX_CMD_FLG_SEQ_CTL
|
764 IWM_TX_CMD_FLG_BT_DIS
);
765 req
->tx_cmd
[1].rate_n_flags
=
766 iwm_scan_rate_n_flags(sc
, IEEE80211_CHAN_5GHZ
, 1/*XXX*/);
767 req
->tx_cmd
[1].sta_id
= sc
->sc_aux_sta
.sta_id
;
769 /* Check if we're doing an active directed scan. */
770 nssid
= MIN(ss
->ss_nssid
, IWM_PROBE_OPTION_MAX
);
771 for (i
= 0; i
< nssid
; i
++) {
772 req
->direct_scan
[i
].id
= IEEE80211_ELEMID_SSID
;
773 req
->direct_scan
[i
].len
= MIN(ss
->ss_ssid
[i
].len
,
775 memcpy(req
->direct_scan
[i
].ssid
, ss
->ss_ssid
[i
].ssid
,
776 req
->direct_scan
[i
].len
);
781 htole32(IWM_LMAC_SCAN_FLAG_PRE_CONNECTION
);
783 req
->scan_flags
|= htole32(IWM_LMAC_SCAN_FLAG_PASSIVE
);
785 req
->n_channels
= iwm_lmac_scan_fill_channels(sc
,
786 (struct iwm_scan_channel_cfg_lmac
*)req
->data
, nssid
);
788 ret
= iwm_fill_probe_req(sc
,
789 (struct iwm_scan_probe_req_v1
*)(req
->data
+
790 (sizeof(struct iwm_scan_channel_cfg_lmac
) *
791 sc
->sc_fw
.ucode_capa
.n_scan_channels
)));
793 kfree(req
, M_DEVBUF
);
797 /* Specify the scan plan: We'll do one iteration. */
798 req
->schedule
[0].iterations
= 1;
799 req
->schedule
[0].full_scan_mul
= 1;
801 if (iwm_scan_use_ebs(sc
)) {
802 req
->channel_opt
[0].flags
=
803 htole16(IWM_SCAN_CHANNEL_FLAG_EBS
|
804 IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE
|
805 IWM_SCAN_CHANNEL_FLAG_CACHE_ADD
);
806 req
->channel_opt
[0].non_ebs_ratio
=
807 htole16(IWM_DENSE_EBS_SCAN_RATIO
);
808 req
->channel_opt
[1].flags
=
809 htole16(IWM_SCAN_CHANNEL_FLAG_EBS
|
810 IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE
|
811 IWM_SCAN_CHANNEL_FLAG_CACHE_ADD
);
812 req
->channel_opt
[1].non_ebs_ratio
=
813 htole16(IWM_SPARSE_EBS_SCAN_RATIO
);
816 ret
= iwm_send_cmd(sc
, &hcmd
);
818 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
819 "Scan request was sent successfully\n");
821 kfree(req
, M_DEVBUF
);
826 iwm_lmac_scan_abort(struct iwm_softc
*sc
)
829 struct iwm_host_cmd hcmd
= {
830 .id
= IWM_SCAN_OFFLOAD_ABORT_CMD
,
833 .flags
= IWM_CMD_SYNC
,
837 ret
= iwm_send_cmd_status(sc
, &hcmd
, &status
);
841 if (status
!= IWM_CAN_ABORT_STATUS
) {
843 * The scan abort will return 1 for success or
844 * 2 for "failure". A failure condition can be
845 * due to simply not being in an active scan which
846 * can occur if we send the scan abort before the
847 * microcode has notified us that a scan is completed.
849 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
,
850 "SCAN OFFLOAD ABORT ret %d.\n", status
);
858 iwm_umac_scan_abort(struct iwm_softc
*sc
)
860 struct iwm_umac_scan_abort cmd
= {};
864 cmd
.uid
= htole32(uid
);
866 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Sending scan abort, uid %u\n", uid
);
868 ret
= iwm_send_cmd_pdu(sc
,
869 iwm_cmd_id(IWM_SCAN_ABORT_UMAC
,
870 IWM_ALWAYS_LONG_GROUP
, 0),
871 0, sizeof(cmd
), &cmd
);
877 iwm_scan_stop_wait(struct iwm_softc
*sc
)
879 struct iwm_notification_wait wait_scan_done
;
880 static const uint16_t scan_done_notif
[] = { IWM_SCAN_COMPLETE_UMAC
,
881 IWM_SCAN_OFFLOAD_COMPLETE
, };
884 iwm_init_notification_wait(sc
->sc_notif_wait
, &wait_scan_done
,
885 scan_done_notif
, nitems(scan_done_notif
),
888 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "Preparing to stop scan\n");
890 if (iwm_fw_has_capa(sc
, IWM_UCODE_TLV_CAPA_UMAC_SCAN
))
891 ret
= iwm_umac_scan_abort(sc
);
893 ret
= iwm_lmac_scan_abort(sc
);
896 IWM_DPRINTF(sc
, IWM_DEBUG_SCAN
, "couldn't stop scan\n");
897 iwm_remove_notification(sc
->sc_notif_wait
, &wait_scan_done
);
902 ret
= iwm_wait_notification(sc
->sc_notif_wait
, &wait_scan_done
, hz
);