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