xref: /dragonfly/sys/dev/netif/iwm/if_iwm_scan.c (revision e1c15eeb)
1 /*	$OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2014 genua mbh <info@genua.de>
5  * Copyright (c) 2014 Fixup Software Ltd.
6  *
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.
10  *
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.
18  */
19 
20 /*-
21  * Based on BSD-licensed source modules in the Linux iwlwifi driver,
22  * which were used as the reference documentation for this implementation.
23  *
24  * Driver version we are currently based off of is
25  * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd)
26  *
27  ***********************************************************************
28  *
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.
31  *
32  * GPL LICENSE SUMMARY
33  *
34  * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
35  *
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.
39  *
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.
44  *
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,
48  * USA
49  *
50  * The full GNU General Public License is included in this distribution
51  * in the file called COPYING.
52  *
53  * Contact Information:
54  *  Intel Linux Wireless <ilw@linux.intel.com>
55  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
56  *
57  *
58  * BSD LICENSE
59  *
60  * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
61  * All rights reserved.
62  *
63  * Redistribution and use in source and binary forms, with or without
64  * modification, are permitted provided that the following conditions
65  * are met:
66  *
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
72  *    distribution.
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.
76  *
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.
88  */
89 
90 /*-
91  * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
92  *
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.
96  *
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.
104  */
105 #include <sys/param.h>
106 #include <sys/bus.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>
116 
117 #include <machine/endian.h>
118 
119 #include <bus/pci/pcivar.h>
120 #include <bus/pci/pcireg.h>
121 
122 #include <net/bpf.h>
123 
124 #include <net/if.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>
130 
131 #include <netinet/in.h>
132 #include <netinet/in_systm.h>
133 #include <netinet/if_ether.h>
134 #include <netinet/ip.h>
135 
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>
140 
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"
147 
148 /*
149  * BEGIN mvm/scan.c
150  */
151 
152 #define IWM_DENSE_EBS_SCAN_RATIO 5
153 #define IWM_SPARSE_EBS_SCAN_RATIO 1
154 
155 static uint16_t
156 iwm_scan_rx_chain(struct iwm_softc *sc)
157 {
158 	uint16_t rx_chain;
159 	uint8_t rx_ant;
160 
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);
167 }
168 
169 static uint32_t
170 iwm_scan_rxon_flags(struct ieee80211_channel *c)
171 {
172 	if (IEEE80211_IS_CHAN_2GHZ(c))
173 		return htole32(IWM_PHY_BAND_24);
174 	else
175 		return htole32(IWM_PHY_BAND_5);
176 }
177 
178 static uint32_t
179 iwm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
180 {
181 	uint32_t tx_ant;
182 	int i, ind;
183 
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;
189 			break;
190 		}
191 	}
192 	tx_ant = (1 << sc->sc_scan_last_antenna) << IWM_RATE_MCS_ANT_POS;
193 
194 	if ((flags & IEEE80211_CHAN_2GHZ) && !no_cck)
195 		return htole32(IWM_RATE_1M_PLCP | IWM_RATE_MCS_CCK_MSK |
196 				   tx_ant);
197 	else
198 		return htole32(IWM_RATE_6M_PLCP | tx_ant);
199 }
200 
201 static inline boolean_t
202 iwm_rrm_scan_needed(struct iwm_softc *sc)
203 {
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);
206 }
207 
208 #ifdef IWM_DEBUG
209 static const char *
210 iwm_ebs_status_str(enum iwm_scan_ebs_status status)
211 {
212 	switch (status) {
213 	case IWM_SCAN_EBS_SUCCESS:
214 		return "successful";
215 	case IWM_SCAN_EBS_INACTIVE:
216 		return "inactive";
217 	case IWM_SCAN_EBS_FAILED:
218 	case IWM_SCAN_EBS_CHAN_NOT_FOUND:
219 	default:
220 		return "failed";
221 	}
222 }
223 
224 static const char *
225 iwm_offload_status_str(enum iwm_scan_offload_complete_status status)
226 {
227 	return (status == IWM_SCAN_OFFLOAD_ABORTED) ? "aborted" : "completed";
228 }
229 #endif
230 
231 void
232 iwm_rx_lmac_scan_complete_notif(struct iwm_softc *sc,
233     struct iwm_rx_packet *pkt)
234 {
235 	struct iwm_periodic_scan_complete *scan_notif = (void *)pkt->data;
236 
237 	/* If this happens, the firmware has mistakenly sent an LMAC
238 	 * notification during UMAC scans -- warn and ignore it.
239 	 */
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",
243 		    __func__);
244 		return;
245 	}
246 
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));
250 
251 	sc->last_ebs_successful =
252 			scan_notif->ebs_status == IWM_SCAN_EBS_SUCCESS ||
253 			scan_notif->ebs_status == IWM_SCAN_EBS_INACTIVE;
254 
255 }
256 
257 void
258 iwm_rx_umac_scan_complete_notif(struct iwm_softc *sc,
259     struct iwm_rx_packet *pkt)
260 {
261 	struct iwm_umac_scan_complete *notif = (void *)pkt->data;
262 
263 	IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
264 	    "Scan completed, uid %u, status %s, EBS status %s\n",
265 	    le32toh(notif->uid),
266 	    iwm_offload_status_str(notif->status),
267 	    iwm_ebs_status_str(notif->ebs_status));
268 
269 	if (notif->ebs_status != IWM_SCAN_EBS_SUCCESS &&
270 	    notif->ebs_status != IWM_SCAN_EBS_INACTIVE)
271 		sc->last_ebs_successful = FALSE;
272 }
273 
274 static int
275 iwm_scan_skip_channel(struct ieee80211_channel *c)
276 {
277 	if (IEEE80211_IS_CHAN_2GHZ(c) && IEEE80211_IS_CHAN_B(c))
278 		return 0;
279 	else if (IEEE80211_IS_CHAN_5GHZ(c) && IEEE80211_IS_CHAN_A(c))
280 		return 0;
281 	else
282 		return 1;
283 }
284 
285 static uint8_t
286 iwm_lmac_scan_fill_channels(struct iwm_softc *sc,
287     struct iwm_scan_channel_cfg_lmac *chan, int n_ssids)
288 {
289 	struct ieee80211com *ic = &sc->sc_ic;
290 	struct ieee80211_scan_state *ss = ic->ic_scan;
291 	struct ieee80211_channel *c;
292 	uint8_t nchan;
293 	int j;
294 
295 	for (nchan = j = 0;
296 	    j < ss->ss_last && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
297 	    j++) {
298 		c = ss->ss_chans[j];
299 		/*
300 		 * Catch other channels, in case we have 900MHz channels or
301 		 * something in the chanlist.
302 		 */
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);
307 			continue;
308 		}
309 
310 		IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
311 		    "Adding channel %d (%d Mhz) to the list\n",
312 		    nchan, c->ic_freq);
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);
322 		chan++;
323 		nchan++;
324 	}
325 
326 	return nchan;
327 }
328 
329 static uint8_t
330 iwm_umac_scan_fill_channels(struct iwm_softc *sc,
331     struct iwm_scan_channel_cfg_umac *chan, int n_ssids)
332 {
333 	struct ieee80211com *ic = &sc->sc_ic;
334 	struct ieee80211_scan_state *ss = ic->ic_scan;
335 	struct ieee80211_channel *c;
336 	uint8_t nchan;
337 	int j;
338 
339 	for (nchan = j = 0;
340 	    j < ss->ss_last && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
341 	    j++) {
342 		c = ss->ss_chans[j];
343 		/*
344 		 * Catch other channels, in case we have 900MHz channels or
345 		 * something in the chanlist.
346 		 */
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);
351 			continue;
352 		}
353 
354 		IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
355 		    "Adding channel %d (%d Mhz) to the list\n",
356 		    nchan, c->ic_freq);
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));
361 		chan++;
362 		nchan++;
363 	}
364 
365 	return nchan;
366 }
367 
368 static int
369 iwm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq)
370 {
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);
376 	uint8_t *frm, *pos;
377 
378 	memset(preq, 0, sizeof(*preq));
379 
380 	/* Ensure enough space for header and SSID IE. */
381 	if (remain < sizeof(*wh) + 2)
382 		return ENOBUFS;
383 
384 	/*
385 	 * Build a probe request frame.  Most of the following code is a
386 	 * copy & paste of what is done in net80211.
387 	 */
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 */
396 
397 	frm = (uint8_t *)(wh + 1);
398 	frm = ieee80211_add_ssid(frm, NULL, 0);
399 
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;
404 
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)
409 			return ENOBUFS;
410 	} else if (remain < 2 + rs->rs_nrates) {
411 		return ENOBUFS;
412 	}
413 	preq->band_data[0].offset = htole16(frm - (uint8_t *)wh);
414 	pos = frm;
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);
419 	remain -= frm - pos;
420 
421 	if (iwm_rrm_scan_needed(sc)) {
422 		if (remain < 3)
423 			return ENOBUFS;
424 		*frm++ = IEEE80211_ELEMID_DSPARMS;
425 		*frm++ = 1;
426 		*frm++ = 0;
427 		remain -= 3;
428 	}
429 
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)
435 				return ENOBUFS;
436 		} else if (remain < 2 + rs->rs_nrates) {
437 			return ENOBUFS;
438 		}
439 		preq->band_data[1].offset = htole16(frm - (uint8_t *)wh);
440 		pos = frm;
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);
445 		remain -= frm - pos;
446 	}
447 
448 	/* Send 11n IEs on both 2GHz and 5GHz bands. */
449 	preq->common_data.offset = htole16(frm - (uint8_t *)wh);
450 	pos = frm;
451 #if 0
452 	if (ic->ic_flags & IEEE80211_F_HTON) {
453 		if (remain < 28)
454 			return ENOBUFS;
455 		frm = ieee80211_add_htcaps(frm, ic);
456 		/* XXX add WME info? */
457 	}
458 #endif
459 	preq->common_data.len = htole16(frm - pos);
460 
461 	return 0;
462 }
463 
464 int
465 iwm_config_umac_scan(struct iwm_softc *sc)
466 {
467 	struct ieee80211com *ic = &sc->sc_ic;
468 	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
469 
470 	struct iwm_scan_config *scan_config;
471 	int ret, j, nchan;
472 	size_t cmd_size;
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,
477 	};
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);
485 
486 	cmd_size = sizeof(*scan_config) + sc->sc_fw.ucode_capa.n_scan_channels;
487 
488 	scan_config = kmalloc(cmd_size, M_DEVBUF, M_WAITOK | M_ZERO);
489 	if (scan_config == NULL)
490 		return ENOMEM;
491 
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));
496 
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);
504 
505 	IEEE80211_ADDR_COPY(scan_config->mac_addr,
506 	    vap ? vap->iv_myaddr : ic->ic_macaddr);
507 
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;
512 
513 	for (nchan = j = 0;
514 	    j < ic->ic_nchans && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
515 	    j++) {
516 		c = &ic->ic_channels[j];
517 		/* For 2GHz, only populate 11b channels */
518 		/* For 5GHz, only populate 11a channels */
519 		/*
520 		 * Catch other channels, in case we have 900MHz channels or
521 		 * something in the chanlist.
522 		 */
523 		if (iwm_scan_skip_channel(c))
524 			continue;
525 		scan_config->channel_array[nchan++] =
526 		    ieee80211_mhz2ieee(c->ic_freq, 0);
527 	}
528 
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);
540 
541 	hcmd.data[0] = scan_config;
542 	hcmd.len[0] = cmd_size;
543 
544 	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending UMAC scan config\n");
545 
546 	ret = iwm_send_cmd(sc, &hcmd);
547 	if (!ret)
548 		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
549 		    "UMAC scan config was sent successfully\n");
550 
551 	kfree(scan_config, M_DEVBUF);
552 	return ret;
553 }
554 
555 static boolean_t
556 iwm_scan_use_ebs(struct iwm_softc *sc)
557 {
558 	const struct iwm_ucode_capabilities *capa = &sc->sc_fw.ucode_capa;
559 
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.
565 	 */
566 	return ((capa->flags & IWM_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
567 		sc->last_ebs_successful);
568 }
569 
570 static int
571 iwm_scan_size(struct iwm_softc *sc)
572 {
573 	int base_size;
574 
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;
578 		else
579 			base_size = IWM_SCAN_REQ_UMAC_SIZE_V1;
580 
581 		return base_size +
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);
585 	} else {
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);
590 	}
591 }
592 
593 int
594 iwm_umac_scan(struct iwm_softc *sc)
595 {
596 	struct iwm_host_cmd hcmd = {
597 		.id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_ALWAYS_LONG_GROUP, 0),
598 		.len = { 0, },
599 		.data = { NULL, },
600 		.flags = IWM_CMD_SYNC,
601 	};
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 *tail;
605 	size_t req_len;
606 	uint16_t general_flags;
607 	uint8_t channel_flags, i, nssid;
608 	int ret;
609 
610 	req_len = iwm_scan_size(sc);
611 	if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
612 		return ENOMEM;
613 	req = kmalloc(req_len, M_DEVBUF, M_WAITOK | M_ZERO);
614 	if (req == NULL)
615 		return ENOMEM;
616 
617 	hcmd.len[0] = (uint16_t)req_len;
618 	hcmd.data[0] = (void *)req;
619 
620 	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n");
621 
622 	nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX);
623 
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;
630 	if (nssid != 0)
631 		general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
632 	else
633 		general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE;
634 
635 	channel_flags = 0;
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;
640 
641 	req->general_flags = htole16(general_flags);
642 	req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
643 
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);
656 
657 		tail = (void *)((char *)&req->v7.data +
658 		    sizeof(struct iwm_scan_channel_cfg_umac) *
659 		    sc->sc_fw.ucode_capa.n_scan_channels);
660 	} else {
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);
669 
670 		tail = (void *)((char *)&req->v1.data +
671 		    sizeof(struct iwm_scan_channel_cfg_umac) *
672 		    sc->sc_fw.ucode_capa.n_scan_channels);
673 	}
674 
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,
679 		    IEEE80211_NWID_LEN);
680 		memcpy(tail->direct_scan[i].ssid, ss->ss_ssid[i].ssid,
681 		    tail->direct_scan[i].len);
682 		/* XXX debug */
683 	}
684 
685 	ret = iwm_fill_probe_req(sc, &tail->preq);
686 	if (ret) {
687 		kfree(req, M_DEVBUF);
688 		return ret;
689 	}
690 
691 	/* Specify the scan plan: We'll do one iteration. */
692 	tail->schedule[0].interval = 0;
693 	tail->schedule[0].iter_count = 1;
694 
695 	ret = iwm_send_cmd(sc, &hcmd);
696 	if (!ret)
697 		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
698 		    "Scan request was sent successfully\n");
699 	kfree(req, M_DEVBUF);
700 	return ret;
701 }
702 
703 int
704 iwm_lmac_scan(struct iwm_softc *sc)
705 {
706 	struct iwm_host_cmd hcmd = {
707 		.id = IWM_SCAN_OFFLOAD_REQUEST_CMD,
708 		.len = { 0, },
709 		.data = { NULL, },
710 		.flags = IWM_CMD_SYNC,
711 	};
712 	struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan;
713 	struct iwm_scan_req_lmac *req;
714 	size_t req_len;
715 	uint8_t i, nssid;
716 	int ret;
717 
718 	IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
719 	    "Handling ieee80211 scan request\n");
720 
721 	req_len = iwm_scan_size(sc);
722 	if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
723 		return ENOMEM;
724 	req = kmalloc(req_len, M_DEVBUF, M_WAITOK | M_ZERO);
725 	if (req == NULL)
726 		return ENOMEM;
727 
728 	hcmd.len[0] = (uint16_t)req_len;
729 	hcmd.data[0] = (void *)req;
730 
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;
738 
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);
742 	req->delay = 0;
743 
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);
749 
750 	req->flags = iwm_scan_rxon_flags(sc->sc_ic.ic_scan->ss_chans[0]);
751 
752 	req->filter_flags =
753 	    htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON);
754 
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;
761 
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;
768 
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,
774 		    IEEE80211_NWID_LEN);
775 		memcpy(req->direct_scan[i].ssid, ss->ss_ssid[i].ssid,
776 		    req->direct_scan[i].len);
777 		/* XXX debug */
778 	}
779 	if (nssid != 0) {
780 		req->scan_flags |=
781 		    htole32(IWM_LMAC_SCAN_FLAG_PRE_CONNECTION);
782 	} else
783 		req->scan_flags |= htole32(IWM_LMAC_SCAN_FLAG_PASSIVE);
784 
785 	req->n_channels = iwm_lmac_scan_fill_channels(sc,
786 	    (struct iwm_scan_channel_cfg_lmac *)req->data, nssid);
787 
788 	ret = iwm_fill_probe_req(sc,
789 			    (struct iwm_scan_probe_req *)(req->data +
790 			    (sizeof(struct iwm_scan_channel_cfg_lmac) *
791 			    sc->sc_fw.ucode_capa.n_scan_channels)));
792 	if (ret) {
793 		kfree(req, M_DEVBUF);
794 		return ret;
795 	}
796 
797 	/* Specify the scan plan: We'll do one iteration. */
798 	req->schedule[0].iterations = 1;
799 	req->schedule[0].full_scan_mul = 1;
800 
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);
814 	}
815 
816 	ret = iwm_send_cmd(sc, &hcmd);
817 	if (!ret) {
818 		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
819 		    "Scan request was sent successfully\n");
820 	}
821 	kfree(req, M_DEVBUF);
822 	return ret;
823 }
824 
825 static int
826 iwm_lmac_scan_abort(struct iwm_softc *sc)
827 {
828 	int ret;
829 	struct iwm_host_cmd hcmd = {
830 		.id = IWM_SCAN_OFFLOAD_ABORT_CMD,
831 		.len = { 0, },
832 		.data = { NULL, },
833 		.flags = IWM_CMD_SYNC,
834 	};
835 	uint32_t status;
836 
837 	ret = iwm_send_cmd_status(sc, &hcmd, &status);
838 	if (ret)
839 		return ret;
840 
841 	if (status != IWM_CAN_ABORT_STATUS) {
842 		/*
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.
848 		 */
849 		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
850 		    "SCAN OFFLOAD ABORT ret %d.\n", status);
851 		ret = ENOENT;
852 	}
853 
854 	return ret;
855 }
856 
857 static int
858 iwm_umac_scan_abort(struct iwm_softc *sc)
859 {
860 	struct iwm_umac_scan_abort cmd = {};
861 	int uid, ret;
862 
863 	uid = 0;
864 	cmd.uid = htole32(uid);
865 
866 	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending scan abort, uid %u\n", uid);
867 
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);
872 
873 	return ret;
874 }
875 
876 int
877 iwm_scan_stop_wait(struct iwm_softc *sc)
878 {
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, };
882 	int ret;
883 
884 	iwm_init_notification_wait(sc->sc_notif_wait, &wait_scan_done,
885 				   scan_done_notif, nitems(scan_done_notif),
886 				   NULL, NULL);
887 
888 	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Preparing to stop scan\n");
889 
890 	if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
891 		ret = iwm_umac_scan_abort(sc);
892 	else
893 		ret = iwm_lmac_scan_abort(sc);
894 
895 	if (ret) {
896 		IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "couldn't stop scan\n");
897 		iwm_remove_notification(sc->sc_notif_wait, &wait_scan_done);
898 		return ret;
899 	}
900 
901 	IWM_UNLOCK(sc);
902 	ret = iwm_wait_notification(sc->sc_notif_wait, &wait_scan_done, hz);
903 	IWM_LOCK(sc);
904 
905 	return ret;
906 }
907