struct iwm_scan_cmd *cmd = sc->sc_scan_cmd; int is_assoc = 0; int ret; uint32_t status; int basic_ssid = !(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID); sc->sc_scanband = flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ); IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); memset(cmd, 0, sc->sc_scan_cmd_len); cmd->quiet_time = htole16(IWM_ACTIVE_QUIET_TIME); cmd->quiet_plcp_th = htole16(IWM_PLCP_QUIET_THRESH); cmd->rxchain_sel_flags = iwm_mvm_scan_rx_chain(sc); cmd->max_out_time = iwm_mvm_scan_max_out_time(sc, 0, is_assoc); cmd->suspend_time = iwm_mvm_scan_suspend_time(sc, is_assoc); cmd->rxon_flags = iwm_mvm_scan_rxon_flags(sc, flags); cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON); cmd->type = htole32(IWM_SCAN_TYPE_FORCED); cmd->repeats = htole32(1); /* * If the user asked for passive scan, don't change to active scan if * you see any activity on the channel - remain passive. */ if (n_ssids > 0) { cmd->passive2active = htole16(1);
int iwm_mvm_config_umac_scan(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwm_scan_config *scan_config; int ret, j, nchan; size_t cmd_size; struct ieee80211_channel *c; struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_CFG_CMD, IWM_ALWAYS_LONG_GROUP, 0), .flags = IWM_CMD_SYNC, }; static const uint32_t rates = (IWM_SCAN_CONFIG_RATE_1M | IWM_SCAN_CONFIG_RATE_2M | IWM_SCAN_CONFIG_RATE_5M | IWM_SCAN_CONFIG_RATE_11M | IWM_SCAN_CONFIG_RATE_6M | IWM_SCAN_CONFIG_RATE_9M | IWM_SCAN_CONFIG_RATE_12M | IWM_SCAN_CONFIG_RATE_18M | IWM_SCAN_CONFIG_RATE_24M | IWM_SCAN_CONFIG_RATE_36M | IWM_SCAN_CONFIG_RATE_48M | IWM_SCAN_CONFIG_RATE_54M); cmd_size = sizeof(*scan_config) + sc->ucode_capa.n_scan_channels; scan_config = malloc(cmd_size, M_DEVBUF, M_NOWAIT | M_ZERO); if (scan_config == NULL) return ENOMEM; scan_config->tx_chains = htole32(iwm_mvm_get_valid_tx_ant(sc)); scan_config->rx_chains = htole32(iwm_mvm_get_valid_rx_ant(sc)); scan_config->legacy_rates = htole32(rates | IWM_SCAN_CONFIG_SUPPORTED_RATE(rates)); /* These timings correspond to iwlwifi's UNASSOC scan. */ scan_config->dwell_active = 10; scan_config->dwell_passive = 110; scan_config->dwell_fragmented = 44; scan_config->dwell_extended = 90; scan_config->out_of_channel_time = htole32(0); scan_config->suspend_time = htole32(0); IEEE80211_ADDR_COPY(scan_config->mac_addr, vap ? vap->iv_myaddr : ic->ic_macaddr); scan_config->bcast_sta_id = sc->sc_aux_sta.sta_id; scan_config->channel_flags = IWM_CHANNEL_FLAG_EBS | IWM_CHANNEL_FLAG_ACCURATE_EBS | IWM_CHANNEL_FLAG_EBS_ADD | IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; for (nchan = j = 0; j < ic->ic_nchans && nchan < sc->ucode_capa.n_scan_channels; j++) { c = &ic->ic_channels[j]; /* For 2GHz, only populate 11b channels */ /* For 5GHz, only populate 11a channels */ /* * Catch other channels, in case we have 900MHz channels or * something in the chanlist. */ if (iwm_mvm_scan_skip_channel(c)) continue; scan_config->channel_array[nchan++] = ieee80211_mhz2ieee(c->ic_freq, 0); } scan_config->flags = htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE | IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID | IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES | IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES | IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR | IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| IWM_SCAN_CONFIG_N_CHANNELS(nchan) | IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED); hcmd.data[0] = scan_config; hcmd.len[0] = cmd_size; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Sending UMAC scan config\n"); ret = iwm_send_cmd(sc, &hcmd); if (!ret) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan config was sent successfully\n"); free(scan_config, M_DEVBUF); return ret; } static boolean_t iwm_mvm_scan_use_ebs(struct iwm_softc *sc) { const struct iwm_ucode_capabilities *capa = &sc->ucode_capa; /* We can only use EBS if: * 1. the feature is supported; * 2. the last EBS was successful; * 3. if only single scan, the single scan EBS API is supported; * 4. it's not a p2p find operation. */ return ((capa->flags & IWM_UCODE_TLV_FLAGS_EBS_SUPPORT) && sc->last_ebs_successful); } int iwm_mvm_umac_scan(struct iwm_softc *sc) { struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_ALWAYS_LONG_GROUP, 0), .len = { 0, }, .data = { NULL, }, .flags = IWM_CMD_SYNC, }; struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan; struct iwm_scan_req_umac *req; struct iwm_scan_req_umac_tail *tail; size_t req_len; uint8_t i, nssid; int ret; req_len = sizeof(struct iwm_scan_req_umac) + (sizeof(struct iwm_scan_channel_cfg_umac) * sc->ucode_capa.n_scan_channels) + sizeof(struct iwm_scan_req_umac_tail); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); /* These timings correspond to iwlwifi's UNASSOC scan. */ req->active_dwell = 10; req->passive_dwell = 110; req->fragmented_dwell = 44; req->extended_dwell = 90; req->max_out_time = 0; req->suspend_time = 0; req->scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH); nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); req->n_channels = iwm_mvm_umac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_umac *)req->data, nssid); req->general_flags = htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL | IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE | IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL); tail = (void *)((char *)&req->data + sizeof(struct iwm_scan_channel_cfg_umac) * sc->ucode_capa.n_scan_channels); /* Check if we're doing an active directed scan. */ for (i = 0; i < nssid; i++) { tail->direct_scan[i].id = IEEE80211_ELEMID_SSID; tail->direct_scan[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); memcpy(tail->direct_scan[i].ssid, ss->ss_ssid[i].ssid, tail->direct_scan[i].len); /* XXX debug */ } if (nssid != 0) { req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT); } else req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE); if (iwm_mvm_scan_use_ebs(sc)) req->channel_flags = IWM_SCAN_CHANNEL_FLAG_EBS | IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWM_SCAN_CHANNEL_FLAG_CACHE_ADD; if (iwm_mvm_rrm_scan_needed(sc)) req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED); ret = iwm_mvm_fill_probe_req(sc, &tail->preq); if (ret) { free(req, M_DEVBUF); return ret; } /* Specify the scan plan: We'll do one iteration. */ tail->schedule[0].interval = 0; tail->schedule[0].iter_count = 1; ret = iwm_send_cmd(sc, &hcmd); if (!ret) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Scan request was sent successfully\n"); free(req, M_DEVBUF); return ret; } int iwm_mvm_lmac_scan(struct iwm_softc *sc) { struct iwm_host_cmd hcmd = { .id = IWM_SCAN_OFFLOAD_REQUEST_CMD, .len = { 0, }, .data = { NULL, }, .flags = IWM_CMD_SYNC, }; struct ieee80211_scan_state *ss = sc->sc_ic.ic_scan; struct iwm_scan_req_lmac *req; size_t req_len; uint8_t i, nssid; int ret; IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Handling ieee80211 scan request\n"); req_len = sizeof(struct iwm_scan_req_lmac) + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->ucode_capa.n_scan_channels) + sizeof(struct iwm_scan_probe_req); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = malloc(req_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; /* These timings correspond to iwlwifi's UNASSOC scan. */ req->active_dwell = 10; req->passive_dwell = 110; req->fragmented_dwell = 44; req->extended_dwell = 90; req->max_out_time = 0; req->suspend_time = 0; req->scan_prio = htole32(IWM_SCAN_PRIORITY_HIGH); req->rx_chain_select = iwm_mvm_scan_rx_chain(sc); req->iter_num = htole32(1); req->delay = 0; req->scan_flags = htole32(IWM_MVM_LMAC_SCAN_FLAG_PASS_ALL | IWM_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE | IWM_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL); if (iwm_mvm_rrm_scan_needed(sc)) req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED); req->flags = iwm_mvm_scan_rxon_flags(sc->sc_ic.ic_scan->ss_chans[0]); req->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON); /* Tx flags 2 GHz. */ req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[0].rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/); req->tx_cmd[0].sta_id = sc->sc_aux_sta.sta_id; /* Tx flags 5 GHz. */ req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[1].rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/); req->tx_cmd[1].sta_id = sc->sc_aux_sta.sta_id; /* Check if we're doing an active directed scan. */ nssid = MIN(ss->ss_nssid, IWM_PROBE_OPTION_MAX); for (i = 0; i < nssid; i++) { req->direct_scan[i].id = IEEE80211_ELEMID_SSID; req->direct_scan[i].len = MIN(ss->ss_ssid[i].len, IEEE80211_NWID_LEN); memcpy(req->direct_scan[i].ssid, ss->ss_ssid[i].ssid, req->direct_scan[i].len); /* XXX debug */ } if (nssid != 0) { req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION); } else req->scan_flags |= htole32(IWM_MVM_LMAC_SCAN_FLAG_PASSIVE); req->n_channels = iwm_mvm_lmac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_lmac *)req->data, nssid); ret = iwm_mvm_fill_probe_req(sc, (struct iwm_scan_probe_req *)(req->data + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->ucode_capa.n_scan_channels))); if (ret) { free(req, M_DEVBUF); return ret; } /* Specify the scan plan: We'll do one iteration. */ req->schedule[0].iterations = 1; req->schedule[0].full_scan_mul = 1; if (iwm_mvm_scan_use_ebs(sc)) { req->channel_opt[0].flags = htole16(IWM_SCAN_CHANNEL_FLAG_EBS | IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWM_SCAN_CHANNEL_FLAG_CACHE_ADD); req->channel_opt[0].non_ebs_ratio = htole16(IWM_DENSE_EBS_SCAN_RATIO); req->channel_opt[1].flags = htole16(IWM_SCAN_CHANNEL_FLAG_EBS | IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWM_SCAN_CHANNEL_FLAG_CACHE_ADD); req->channel_opt[1].non_ebs_ratio = htole16(IWM_SPARSE_EBS_SCAN_RATIO); } ret = iwm_send_cmd(sc, &hcmd); if (!ret) { IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "Scan request was sent successfully\n"); } free(req, M_DEVBUF); return ret; }