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/cdefs.h>
106#include "opt_wlan.h"
107#include "opt_iwm.h"
108
109#include <sys/param.h>
110#include <sys/bus.h>
111#include <sys/conf.h>
112#include <sys/endian.h>
113#include <sys/firmware.h>
114#include <sys/kernel.h>
115#include <sys/malloc.h>
116#include <sys/mbuf.h>
117#include <sys/mutex.h>
118#include <sys/module.h>
119#include <sys/proc.h>
120#include <sys/rman.h>
121#include <sys/socket.h>
122#include <sys/sockio.h>
123#include <sys/sysctl.h>
124#include <sys/linker.h>
125
126#include <machine/bus.h>
127#include <machine/endian.h>
128#include <machine/resource.h>
129
130#include <dev/pci/pcivar.h>
131#include <dev/pci/pcireg.h>
132
133#include <net/bpf.h>
134
135#include <net/if.h>
136#include <net/if_var.h>
137#include <net/if_arp.h>
138#include <net/if_dl.h>
139#include <net/if_media.h>
140#include <net/if_types.h>
141
142#include <netinet/in.h>
143#include <netinet/in_systm.h>
144#include <netinet/if_ether.h>
145#include <netinet/ip.h>
146
147#include <net80211/ieee80211_var.h>
148#include <net80211/ieee80211_regdomain.h>
149#include <net80211/ieee80211_ratectl.h>
150#include <net80211/ieee80211_radiotap.h>
151
152#include <dev/iwm/if_iwmreg.h>
153#include <dev/iwm/if_iwmvar.h>
154#include <dev/iwm/if_iwm_debug.h>
155#include <dev/iwm/if_iwm_notif_wait.h>
156#include <dev/iwm/if_iwm_util.h>
157#include <dev/iwm/if_iwm_scan.h>
158
159/*
160 * BEGIN mvm/scan.c
161 */
162
163#define IWM_DENSE_EBS_SCAN_RATIO 5
164#define IWM_SPARSE_EBS_SCAN_RATIO 1
165
166static uint16_t
167iwm_scan_rx_chain(struct iwm_softc *sc)
168{
169	uint16_t rx_chain;
170	uint8_t rx_ant;
171
172	rx_ant = iwm_get_valid_rx_ant(sc);
173	rx_chain = rx_ant << IWM_PHY_RX_CHAIN_VALID_POS;
174	rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
175	rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_SEL_POS;
176	rx_chain |= 0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS;
177	return htole16(rx_chain);
178}
179
180static uint32_t
181iwm_scan_rxon_flags(struct ieee80211_channel *c)
182{
183	if (IEEE80211_IS_CHAN_2GHZ(c))
184		return htole32(IWM_PHY_BAND_24);
185	else
186		return htole32(IWM_PHY_BAND_5);
187}
188
189static uint32_t
190iwm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
191{
192	uint32_t tx_ant;
193	int i, ind;
194
195	for (i = 0, ind = sc->sc_scan_last_antenna;
196	    i < IWM_RATE_MCS_ANT_NUM; i++) {
197		ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM;
198		if (iwm_get_valid_tx_ant(sc) & (1 << ind)) {
199			sc->sc_scan_last_antenna = ind;
200			break;
201		}
202	}
203	tx_ant = (1 << sc->sc_scan_last_antenna) << IWM_RATE_MCS_ANT_POS;
204
205	if ((flags & IEEE80211_CHAN_2GHZ) && !no_cck)
206		return htole32(IWM_RATE_1M_PLCP | IWM_RATE_MCS_CCK_MSK |
207				   tx_ant);
208	else
209		return htole32(IWM_RATE_6M_PLCP | tx_ant);
210}
211
212static inline boolean_t
213iwm_rrm_scan_needed(struct iwm_softc *sc)
214{
215	/* require rrm scan whenever the fw supports it */
216	return iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT);
217}
218
219#ifdef IWM_DEBUG
220static const char *
221iwm_ebs_status_str(enum iwm_scan_ebs_status status)
222{
223	switch (status) {
224	case IWM_SCAN_EBS_SUCCESS:
225		return "successful";
226	case IWM_SCAN_EBS_INACTIVE:
227		return "inactive";
228	case IWM_SCAN_EBS_FAILED:
229	case IWM_SCAN_EBS_CHAN_NOT_FOUND:
230	default:
231		return "failed";
232	}
233}
234
235static const char *
236iwm_offload_status_str(enum iwm_scan_offload_complete_status status)
237{
238	return (status == IWM_SCAN_OFFLOAD_ABORTED) ? "aborted" : "completed";
239}
240#endif
241
242void
243iwm_rx_lmac_scan_complete_notif(struct iwm_softc *sc,
244    struct iwm_rx_packet *pkt)
245{
246	struct iwm_periodic_scan_complete *scan_notif = (void *)pkt->data;
247
248	/* If this happens, the firmware has mistakenly sent an LMAC
249	 * notification during UMAC scans -- warn and ignore it.
250	 */
251	if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
252		device_printf(sc->sc_dev,
253		    "%s: Mistakenly got LMAC notification during UMAC scan\n",
254		    __func__);
255		return;
256	}
257
258	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Regular scan %s, EBS status %s (FW)\n",
259	    iwm_offload_status_str(scan_notif->status),
260	    iwm_ebs_status_str(scan_notif->ebs_status));
261
262	sc->last_ebs_successful =
263			scan_notif->ebs_status == IWM_SCAN_EBS_SUCCESS ||
264			scan_notif->ebs_status == IWM_SCAN_EBS_INACTIVE;
265
266}
267
268void
269iwm_rx_umac_scan_complete_notif(struct iwm_softc *sc,
270    struct iwm_rx_packet *pkt)
271{
272	struct iwm_umac_scan_complete *notif = (void *)pkt->data;
273
274	IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
275	    "Scan completed, uid %u, status %s, EBS status %s\n",
276	    le32toh(notif->uid),
277	    iwm_offload_status_str(notif->status),
278	    iwm_ebs_status_str(notif->ebs_status));
279
280	if (notif->ebs_status != IWM_SCAN_EBS_SUCCESS &&
281	    notif->ebs_status != IWM_SCAN_EBS_INACTIVE)
282		sc->last_ebs_successful = FALSE;
283}
284
285static int
286iwm_scan_skip_channel(struct ieee80211_channel *c)
287{
288	if (IEEE80211_IS_CHAN_2GHZ(c) && IEEE80211_IS_CHAN_B(c))
289		return 0;
290	else if (IEEE80211_IS_CHAN_5GHZ(c) && IEEE80211_IS_CHAN_A(c))
291		return 0;
292	else
293		return 1;
294}
295
296static uint8_t
297iwm_lmac_scan_fill_channels(struct iwm_softc *sc,
298    struct iwm_scan_channel_cfg_lmac *chan, int n_ssids)
299{
300	struct ieee80211com *ic = &sc->sc_ic;
301	struct ieee80211_scan_state *ss = ic->ic_scan;
302	struct ieee80211_channel *c;
303	uint8_t nchan;
304	int j;
305
306	for (nchan = j = 0;
307	    j < ss->ss_last && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
308	    j++) {
309		c = ss->ss_chans[j];
310		/*
311		 * Catch other channels, in case we have 900MHz channels or
312		 * something in the chanlist.
313		 */
314		if (!IEEE80211_IS_CHAN_2GHZ(c) && !IEEE80211_IS_CHAN_5GHZ(c)) {
315			IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
316			    "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
317			    __func__, c->ic_freq, c->ic_ieee, c->ic_flags);
318			continue;
319		}
320
321		IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
322		    "Adding channel %d (%d Mhz) to the list\n",
323		    nchan, c->ic_freq);
324		chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0));
325		chan->iter_count = htole16(1);
326		chan->iter_interval = htole32(0);
327		chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL);
328		chan->flags |= htole32(IWM_SCAN_CHANNEL_NSSIDS(n_ssids));
329		/* XXX IEEE80211_SCAN_NOBCAST flag is never set. */
330		if (!IEEE80211_IS_CHAN_PASSIVE(c) &&
331		    (!(ss->ss_flags & IEEE80211_SCAN_NOBCAST) || n_ssids != 0))
332			chan->flags |= htole32(IWM_SCAN_CHANNEL_TYPE_ACTIVE);
333		chan++;
334		nchan++;
335	}
336
337	return nchan;
338}
339
340static uint8_t
341iwm_umac_scan_fill_channels(struct iwm_softc *sc,
342    struct iwm_scan_channel_cfg_umac *chan, int n_ssids)
343{
344	struct ieee80211com *ic = &sc->sc_ic;
345	struct ieee80211_scan_state *ss = ic->ic_scan;
346	struct ieee80211_channel *c;
347	uint8_t nchan;
348	int j;
349
350	for (nchan = j = 0;
351	    j < ss->ss_last && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
352	    j++) {
353		c = ss->ss_chans[j];
354		/*
355		 * Catch other channels, in case we have 900MHz channels or
356		 * something in the chanlist.
357		 */
358		if (!IEEE80211_IS_CHAN_2GHZ(c) && !IEEE80211_IS_CHAN_5GHZ(c)) {
359			IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
360			    "%s: skipping channel (freq=%d, ieee=%d, flags=0x%08x)\n",
361			    __func__, c->ic_freq, c->ic_ieee, c->ic_flags);
362			continue;
363		}
364
365		IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_EEPROM,
366		    "Adding channel %d (%d Mhz) to the list\n",
367		    nchan, c->ic_freq);
368		chan->channel_num = ieee80211_mhz2ieee(c->ic_freq, 0);
369		chan->iter_count = 1;
370		chan->iter_interval = htole16(0);
371		chan->flags = htole32(IWM_SCAN_CHANNEL_UMAC_NSSIDS(n_ssids));
372		chan++;
373		nchan++;
374	}
375
376	return nchan;
377}
378
379static int
380iwm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req_v1 *preq)
381{
382	struct ieee80211com *ic = &sc->sc_ic;
383	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
384	struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf;
385	struct ieee80211_rateset *rs;
386	size_t remain = sizeof(preq->buf);
387	uint8_t *frm, *pos;
388
389	memset(preq, 0, sizeof(*preq));
390
391	/* Ensure enough space for header and SSID IE. */
392	if (remain < sizeof(*wh) + 2)
393		return ENOBUFS;
394
395	/*
396	 * Build a probe request frame.  Most of the following code is a
397	 * copy & paste of what is done in net80211.
398	 */
399	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
400	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
401	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
402	IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr);
403	IEEE80211_ADDR_COPY(wh->i_addr2, vap ? vap->iv_myaddr : ic->ic_macaddr);
404	IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr);
405	*(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */
406	*(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */
407
408	frm = (uint8_t *)(wh + 1);
409	frm = ieee80211_add_ssid(frm, NULL, 0);
410
411	/* Tell the firmware where the MAC header is. */
412	preq->mac_header.offset = 0;
413	preq->mac_header.len = htole16(frm - (uint8_t *)wh);
414	remain -= frm - (uint8_t *)wh;
415
416	/* Fill in 2GHz IEs and tell firmware where they are. */
417	rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
418	if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
419		if (remain < 4 + rs->rs_nrates)
420			return ENOBUFS;
421	} else if (remain < 2 + rs->rs_nrates) {
422		return ENOBUFS;
423	}
424	preq->band_data[0].offset = htole16(frm - (uint8_t *)wh);
425	pos = frm;
426	frm = ieee80211_add_rates(frm, rs);
427	if (rs->rs_nrates > IEEE80211_RATE_SIZE)
428		frm = ieee80211_add_xrates(frm, rs);
429	preq->band_data[0].len = htole16(frm - pos);
430	remain -= frm - pos;
431
432	if (iwm_rrm_scan_needed(sc)) {
433		if (remain < 3)
434			return ENOBUFS;
435		*frm++ = IEEE80211_ELEMID_DSPARMS;
436		*frm++ = 1;
437		*frm++ = 0;
438		remain -= 3;
439	}
440
441	if (sc->nvm_data->sku_cap_band_52GHz_enable) {
442		/* Fill in 5GHz IEs. */
443		rs = &ic->ic_sup_rates[IEEE80211_MODE_11A];
444		if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
445			if (remain < 4 + rs->rs_nrates)
446				return ENOBUFS;
447		} else if (remain < 2 + rs->rs_nrates) {
448			return ENOBUFS;
449		}
450		preq->band_data[1].offset = htole16(frm - (uint8_t *)wh);
451		pos = frm;
452		frm = ieee80211_add_rates(frm, rs);
453		if (rs->rs_nrates > IEEE80211_RATE_SIZE)
454			frm = ieee80211_add_xrates(frm, rs);
455		preq->band_data[1].len = htole16(frm - pos);
456		remain -= frm - pos;
457	}
458
459	/* Send 11n IEs on both 2GHz and 5GHz bands. */
460	preq->common_data.offset = htole16(frm - (uint8_t *)wh);
461	pos = frm;
462#if 0
463	if (ic->ic_flags & IEEE80211_F_HTON) {
464		if (remain < 28)
465			return ENOBUFS;
466		frm = ieee80211_add_htcaps(frm, ic);
467		/* XXX add WME info? */
468	}
469#endif
470	preq->common_data.len = htole16(frm - pos);
471
472	return 0;
473}
474
475int
476iwm_config_umac_scan(struct iwm_softc *sc)
477{
478	struct ieee80211com *ic = &sc->sc_ic;
479	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
480
481	struct iwm_scan_config *scan_config;
482	int ret, j, nchan;
483	size_t cmd_size;
484	struct ieee80211_channel *c;
485	struct iwm_host_cmd hcmd = {
486		.id = iwm_cmd_id(IWM_SCAN_CFG_CMD, IWM_ALWAYS_LONG_GROUP, 0),
487		.flags = IWM_CMD_SYNC,
488	};
489	static const uint32_t rates = (IWM_SCAN_CONFIG_RATE_1M |
490	    IWM_SCAN_CONFIG_RATE_2M | IWM_SCAN_CONFIG_RATE_5M |
491	    IWM_SCAN_CONFIG_RATE_11M | IWM_SCAN_CONFIG_RATE_6M |
492	    IWM_SCAN_CONFIG_RATE_9M | IWM_SCAN_CONFIG_RATE_12M |
493	    IWM_SCAN_CONFIG_RATE_18M | IWM_SCAN_CONFIG_RATE_24M |
494	    IWM_SCAN_CONFIG_RATE_36M | IWM_SCAN_CONFIG_RATE_48M |
495	    IWM_SCAN_CONFIG_RATE_54M);
496
497	cmd_size = sizeof(*scan_config) + sc->sc_fw.ucode_capa.n_scan_channels;
498
499	scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO);
500	if (scan_config == NULL)
501		return ENOMEM;
502
503	scan_config->tx_chains = htole32(iwm_get_valid_tx_ant(sc));
504	scan_config->rx_chains = htole32(iwm_get_valid_rx_ant(sc));
505	scan_config->legacy_rates = htole32(rates |
506	    IWM_SCAN_CONFIG_SUPPORTED_RATE(rates));
507
508	/* These timings correspond to iwlwifi's UNASSOC scan. */
509	scan_config->dwell_active = 10;
510	scan_config->dwell_passive = 110;
511	scan_config->dwell_fragmented = 44;
512	scan_config->dwell_extended = 90;
513	scan_config->out_of_channel_time = htole32(0);
514	scan_config->suspend_time = htole32(0);
515
516	IEEE80211_ADDR_COPY(scan_config->mac_addr,
517	    vap ? vap->iv_myaddr : ic->ic_macaddr);
518
519	scan_config->bcast_sta_id = sc->sc_aux_sta.sta_id;
520	scan_config->channel_flags = IWM_CHANNEL_FLAG_EBS |
521	    IWM_CHANNEL_FLAG_ACCURATE_EBS | IWM_CHANNEL_FLAG_EBS_ADD |
522	    IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE;
523
524	for (nchan = j = 0;
525	    j < ic->ic_nchans && nchan < sc->sc_fw.ucode_capa.n_scan_channels;
526	    j++) {
527		c = &ic->ic_channels[j];
528		/* For 2GHz, only populate 11b channels */
529		/* For 5GHz, only populate 11a channels */
530		/*
531		 * Catch other channels, in case we have 900MHz channels or
532		 * something in the chanlist.
533		 */
534		if (iwm_scan_skip_channel(c))
535			continue;
536		scan_config->channel_array[nchan++] =
537		    ieee80211_mhz2ieee(c->ic_freq, 0);
538	}
539
540	scan_config->flags = htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE |
541	    IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS |
542	    IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS |
543	    IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS |
544	    IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID |
545	    IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES |
546	    IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES |
547	    IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR |
548	    IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS|
549	    IWM_SCAN_CONFIG_N_CHANNELS(nchan) |
550	    IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED);
551
552	hcmd.data[0] = scan_config;
553	hcmd.len[0] = cmd_size;
554
555	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending UMAC scan config\n");
556
557	ret = iwm_send_cmd(sc, &hcmd);
558	if (!ret)
559		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
560		    "UMAC scan config was sent successfully\n");
561
562	free(scan_config, M_DEVBUF);
563	return ret;
564}
565
566static boolean_t
567iwm_scan_use_ebs(struct iwm_softc *sc)
568{
569	const struct iwm_ucode_capabilities *capa = &sc->sc_fw.ucode_capa;
570
571	/* We can only use EBS if:
572	 *	1. the feature is supported;
573	 *	2. the last EBS was successful;
574	 *	3. if only single scan, the single scan EBS API is supported;
575	 *	4. it's not a p2p find operation.
576	 */
577	return ((capa->flags & IWM_UCODE_TLV_FLAGS_EBS_SUPPORT) &&
578		sc->last_ebs_successful);
579}
580
581static int
582iwm_scan_size(struct iwm_softc *sc)
583{
584	int base_size;
585
586	if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) {
587		if (iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL))
588			base_size = IWM_SCAN_REQ_UMAC_SIZE_V7;
589		else
590			base_size = IWM_SCAN_REQ_UMAC_SIZE_V1;
591
592		return base_size +
593		    sizeof(struct iwm_scan_channel_cfg_umac) *
594		    sc->sc_fw.ucode_capa.n_scan_channels +
595		    sizeof(struct iwm_scan_req_umac_tail_v1);
596	} else {
597		return sizeof(struct iwm_scan_req_lmac) +
598		    sizeof(struct iwm_scan_channel_cfg_lmac) *
599		    sc->sc_fw.ucode_capa.n_scan_channels +
600		    sizeof(struct iwm_scan_probe_req_v1);
601	}
602}
603
604int
605iwm_umac_scan(struct iwm_softc *sc)
606{
607	struct iwm_host_cmd hcmd = {
608		.id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_ALWAYS_LONG_GROUP, 0),
609		.len = { 0, },
610		.data = { NULL, },
611		.flags = IWM_CMD_SYNC,
612	};
613	struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan;
614	struct iwm_scan_req_umac *req;
615	struct iwm_scan_req_umac_tail_v1 *tail;
616	size_t req_len;
617	uint16_t general_flags;
618	uint8_t channel_flags, i, nssid;
619	int ret;
620
621	req_len = iwm_scan_size(sc);
622	if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
623		return ENOMEM;
624	req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO);
625	if (req == NULL)
626		return ENOMEM;
627
628	hcmd.len[0] = (uint16_t)req_len;
629	hcmd.data[0] = (void *)req;
630
631	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n");
632
633	nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX);
634
635	general_flags = IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL |
636	    IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
637	if (!iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL))
638		general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL;
639	if (iwm_rrm_scan_needed(sc))
640		general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED;
641	if (nssid != 0)
642		general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
643	else
644		general_flags |= IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE;
645
646	channel_flags = 0;
647	if (iwm_scan_use_ebs(sc))
648		channel_flags = IWM_SCAN_CHANNEL_FLAG_EBS |
649		    IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
650		    IWM_SCAN_CHANNEL_FLAG_CACHE_ADD;
651
652	req->general_flags = htole16(general_flags);
653	req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
654
655	/* These timings correspond to iwlwifi's UNASSOC scan. */
656	if (iwm_fw_has_api(sc, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) {
657		req->v7.active_dwell = 10;
658		req->v7.passive_dwell = 110;
659		req->v7.fragmented_dwell = 44;
660		req->v7.adwell_default_n_aps_social = 10;
661		req->v7.adwell_default_n_aps = 2;
662		req->v7.adwell_max_budget = htole16(300);
663		req->v7.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
664		req->v7.channel.flags = channel_flags;
665		req->v7.channel.count = iwm_umac_scan_fill_channels(sc,
666		    (struct iwm_scan_channel_cfg_umac *)req->v7.data, nssid);
667
668		tail = (void *)((char *)&req->v7.data +
669		    sizeof(struct iwm_scan_channel_cfg_umac) *
670		    sc->sc_fw.ucode_capa.n_scan_channels);
671	} else {
672		req->v1.active_dwell = 10;
673		req->v1.passive_dwell = 110;
674		req->v1.fragmented_dwell = 44;
675		req->v1.extended_dwell = 90;
676		req->v1.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH);
677		req->v1.channel.flags = channel_flags;
678		req->v1.channel.count = iwm_umac_scan_fill_channels(sc,
679		    (struct iwm_scan_channel_cfg_umac *)req->v1.data, nssid);
680
681		tail = (void *)((char *)&req->v1.data +
682		    sizeof(struct iwm_scan_channel_cfg_umac) *
683		    sc->sc_fw.ucode_capa.n_scan_channels);
684	}
685
686	/* Check if we're doing an active directed scan. */
687	for (i = 0; i < nssid; i++) {
688		tail->direct_scan[i].id = IEEE80211_ELEMID_SSID;
689		tail->direct_scan[i].len = MIN(ss->ss_ssid[i].len,
690		    IEEE80211_NWID_LEN);
691		memcpy(tail->direct_scan[i].ssid, ss->ss_ssid[i].ssid,
692		    tail->direct_scan[i].len);
693		/* XXX debug */
694	}
695
696	ret = iwm_fill_probe_req(sc, &tail->preq);
697	if (ret) {
698		free(req, M_DEVBUF);
699		return ret;
700	}
701
702	/* Specify the scan plan: We'll do one iteration. */
703	tail->schedule[0].interval = 0;
704	tail->schedule[0].iter_count = 1;
705
706	ret = iwm_send_cmd(sc, &hcmd);
707	if (!ret)
708		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
709		    "Scan request was sent successfully\n");
710	free(req, M_DEVBUF);
711	return ret;
712}
713
714int
715iwm_lmac_scan(struct iwm_softc *sc)
716{
717	struct iwm_host_cmd hcmd = {
718		.id = IWM_SCAN_OFFLOAD_REQUEST_CMD,
719		.len = { 0, },
720		.data = { NULL, },
721		.flags = IWM_CMD_SYNC,
722	};
723	struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan;
724	struct iwm_scan_req_lmac *req;
725	size_t req_len;
726	uint8_t i, nssid;
727	int ret;
728
729	IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
730	    "Handling ieee80211 scan request\n");
731
732	req_len = iwm_scan_size(sc);
733	if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE)
734		return ENOMEM;
735	req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO);
736	if (req == NULL)
737		return ENOMEM;
738
739	hcmd.len[0] = (uint16_t)req_len;
740	hcmd.data[0] = (void *)req;
741
742	/* These timings correspond to iwlwifi's UNASSOC scan. */
743	req->active_dwell = 10;
744	req->passive_dwell = 110;
745	req->fragmented_dwell = 44;
746	req->extended_dwell = 90;
747	req->max_out_time = 0;
748	req->suspend_time = 0;
749
750	req->scan_prio = htole32(IWM_SCAN_PRIORITY_HIGH);
751	req->rx_chain_select = iwm_scan_rx_chain(sc);
752	req->iter_num = htole32(1);
753	req->delay = 0;
754
755	req->scan_flags = htole32(IWM_LMAC_SCAN_FLAG_PASS_ALL |
756	    IWM_LMAC_SCAN_FLAG_ITER_COMPLETE |
757	    IWM_LMAC_SCAN_FLAG_EXTENDED_DWELL);
758	if (iwm_rrm_scan_needed(sc))
759		req->scan_flags |= htole32(IWM_LMAC_SCAN_FLAGS_RRM_ENABLED);
760
761	req->flags = iwm_scan_rxon_flags(sc->sc_ic.ic_scan->ss_chans[0]);
762
763	req->filter_flags =
764	    htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON);
765
766	/* Tx flags 2 GHz. */
767	req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
768	    IWM_TX_CMD_FLG_BT_DIS);
769	req->tx_cmd[0].rate_n_flags =
770	    iwm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/);
771	req->tx_cmd[0].sta_id = sc->sc_aux_sta.sta_id;
772
773	/* Tx flags 5 GHz. */
774	req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
775	    IWM_TX_CMD_FLG_BT_DIS);
776	req->tx_cmd[1].rate_n_flags =
777	    iwm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/);
778	req->tx_cmd[1].sta_id = sc->sc_aux_sta.sta_id;
779
780	/* Check if we're doing an active directed scan. */
781	nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX);
782	for (i = 0; i < nssid; i++) {
783		req->direct_scan[i].id = IEEE80211_ELEMID_SSID;
784		req->direct_scan[i].len = MIN(ss->ss_ssid[i].len,
785		    IEEE80211_NWID_LEN);
786		memcpy(req->direct_scan[i].ssid, ss->ss_ssid[i].ssid,
787		    req->direct_scan[i].len);
788		/* XXX debug */
789	}
790	if (nssid != 0) {
791		req->scan_flags |=
792		    htole32(IWM_LMAC_SCAN_FLAG_PRE_CONNECTION);
793	} else
794		req->scan_flags |= htole32(IWM_LMAC_SCAN_FLAG_PASSIVE);
795
796	req->n_channels = iwm_lmac_scan_fill_channels(sc,
797	    (struct iwm_scan_channel_cfg_lmac *)req->data, nssid);
798
799	ret = iwm_fill_probe_req(sc,
800			    (struct iwm_scan_probe_req_v1 *)(req->data +
801			    (sizeof(struct iwm_scan_channel_cfg_lmac) *
802			    sc->sc_fw.ucode_capa.n_scan_channels)));
803	if (ret) {
804		free(req, M_DEVBUF);
805		return ret;
806	}
807
808	/* Specify the scan plan: We'll do one iteration. */
809	req->schedule[0].iterations = 1;
810	req->schedule[0].full_scan_mul = 1;
811
812	if (iwm_scan_use_ebs(sc)) {
813		req->channel_opt[0].flags =
814			htole16(IWM_SCAN_CHANNEL_FLAG_EBS |
815				IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
816				IWM_SCAN_CHANNEL_FLAG_CACHE_ADD);
817		req->channel_opt[0].non_ebs_ratio =
818			htole16(IWM_DENSE_EBS_SCAN_RATIO);
819		req->channel_opt[1].flags =
820			htole16(IWM_SCAN_CHANNEL_FLAG_EBS |
821				IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
822				IWM_SCAN_CHANNEL_FLAG_CACHE_ADD);
823		req->channel_opt[1].non_ebs_ratio =
824			htole16(IWM_SPARSE_EBS_SCAN_RATIO);
825	}
826
827	ret = iwm_send_cmd(sc, &hcmd);
828	if (!ret) {
829		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
830		    "Scan request was sent successfully\n");
831	}
832	free(req, M_DEVBUF);
833	return ret;
834}
835
836static int
837iwm_lmac_scan_abort(struct iwm_softc *sc)
838{
839	int ret;
840	struct iwm_host_cmd hcmd = {
841		.id = IWM_SCAN_OFFLOAD_ABORT_CMD,
842		.len = { 0, },
843		.data = { NULL, },
844		.flags = IWM_CMD_SYNC,
845	};
846	uint32_t status;
847
848	ret = iwm_send_cmd_status(sc, &hcmd, &status);
849	if (ret)
850		return ret;
851
852	if (status != IWM_CAN_ABORT_STATUS) {
853		/*
854		 * The scan abort will return 1 for success or
855		 * 2 for "failure".  A failure condition can be
856		 * due to simply not being in an active scan which
857		 * can occur if we send the scan abort before the
858		 * microcode has notified us that a scan is completed.
859		 */
860		IWM_DPRINTF(sc, IWM_DEBUG_SCAN,
861		    "SCAN OFFLOAD ABORT ret %d.\n", status);
862		ret = ENOENT;
863	}
864
865	return ret;
866}
867
868static int
869iwm_umac_scan_abort(struct iwm_softc *sc)
870{
871	struct iwm_umac_scan_abort cmd = {};
872	int uid, ret;
873
874	uid = 0;
875	cmd.uid = htole32(uid);
876
877	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending scan abort, uid %u\n", uid);
878
879	ret = iwm_send_cmd_pdu(sc,
880				   iwm_cmd_id(IWM_SCAN_ABORT_UMAC,
881					      IWM_ALWAYS_LONG_GROUP, 0),
882				   0, sizeof(cmd), &cmd);
883
884	return ret;
885}
886
887int
888iwm_scan_stop_wait(struct iwm_softc *sc)
889{
890	struct iwm_notification_wait wait_scan_done;
891	static const uint16_t scan_done_notif[] = { IWM_SCAN_COMPLETE_UMAC,
892						   IWM_SCAN_OFFLOAD_COMPLETE, };
893	int ret;
894
895	iwm_init_notification_wait(sc->sc_notif_wait, &wait_scan_done,
896				   scan_done_notif, nitems(scan_done_notif),
897				   NULL, NULL);
898
899	IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Preparing to stop scan\n");
900
901	if (iwm_fw_has_capa(sc, IWM_UCODE_TLV_CAPA_UMAC_SCAN))
902		ret = iwm_umac_scan_abort(sc);
903	else
904		ret = iwm_lmac_scan_abort(sc);
905
906	if (ret) {
907		IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "couldn't stop scan\n");
908		iwm_remove_notification(sc->sc_notif_wait, &wait_scan_done);
909		return ret;
910	}
911
912	IWM_UNLOCK(sc);
913	ret = iwm_wait_notification(sc->sc_notif_wait, &wait_scan_done, hz);
914	IWM_LOCK(sc);
915
916	return ret;
917}
918