static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, enum ieee80211_band band) { u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; if (iwl_is_associated(priv)) { /* If we're associated, we clamp the maximum passive * dwell time to be 98% of the beacon interval (minus * 2 * channel tune time) */ passive = priv->beacon_int; if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) passive = IWL_PASSIVE_DWELL_BASE; passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; } return passive; }
static void iwl5000_chain_noise_reset(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = &priv->chain_noise_data; int ret; if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { struct iwl_calib_chain_noise_reset_cmd cmd; memset(&cmd, 0, sizeof(cmd)); cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; cmd.hdr.first_group = 0; cmd.hdr.groups_num = 1; cmd.hdr.data_valid = 1; ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, sizeof(cmd), &cmd); if (ret) IWL_ERR(priv, "Could not send REPLY_PHY_CALIBRATION_CMD\n"); data->state = IWL_CHAIN_NOISE_ACCUMULATE; IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n"); } }
static int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { u64 tsf; s32 interval_tm, rem; struct ieee80211_conf *conf = NULL; u16 beacon_int; struct ieee80211_vif *vif = ctx->vif; conf = &priv->hw->conf; lockdep_assert_held(&priv->mutex); memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd)); ctx->timing.timestamp = cpu_to_le64(priv->timestamp); ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval); beacon_int = vif ? vif->bss_conf.beacon_int : 0; /* * TODO: For IBSS we need to get atim_window from mac80211, * for now just always use 0 */ ctx->timing.atim_window = 0; if (ctx->ctxid == IWL_RXON_CTX_PAN && (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) && iwl_is_associated(priv, IWL_RXON_CTX_BSS) && priv->contexts[IWL_RXON_CTX_BSS].vif && priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) { ctx->timing.beacon_interval = priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval; beacon_int = le16_to_cpu(ctx->timing.beacon_interval); } else if (ctx->ctxid == IWL_RXON_CTX_BSS && iwl_is_associated(priv, IWL_RXON_CTX_PAN) && priv->contexts[IWL_RXON_CTX_PAN].vif && priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int && (!iwl_is_associated_ctx(ctx) || !ctx->vif || !ctx->vif->bss_conf.beacon_int)) { ctx->timing.beacon_interval = priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval; beacon_int = le16_to_cpu(ctx->timing.beacon_interval); } else { beacon_int = iwl_adjust_beacon_interval(beacon_int, IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT); ctx->timing.beacon_interval = cpu_to_le16(beacon_int); } ctx->beacon_int = beacon_int; tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ interval_tm = beacon_int * TIME_UNIT; rem = do_div(tsf, interval_tm); ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem); ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1; IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n", le16_to_cpu(ctx->timing.beacon_interval), le32_to_cpu(ctx->timing.beacon_init_val), le16_to_cpu(ctx->timing.atim_window)); return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd, 0, sizeof(ctx->timing), &ctx->timing); }
static void iwl_bg_request_scan(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, request_scan); struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl_scan_cmd), .meta.flags = CMD_SIZE_HUGE, }; struct iwl_scan_cmd *scan; struct ieee80211_conf *conf = NULL; int ret = 0; u32 tx_ant; u16 cmd_len; enum ieee80211_band band; u8 n_probes = 2; u8 rx_chain = priv->hw_params.valid_rx_ant; conf = ieee80211_get_hw_conf(priv->hw); mutex_lock(&priv->mutex); if (!iwl_is_ready(priv)) { IWL_WARNING("request scan called when driver not ready.\n"); goto done; } /* Make sure the scan wasn't cancelled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; /* This should never be called or scheduled if there is currently * a scan active in the hardware. */ if (test_bit(STATUS_SCAN_HW, &priv->status)) { IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " "Ignoring second request.\n"); ret = -EIO; goto done; } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); goto done; } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); goto done; } if (iwl_is_rfkill(priv)) { IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); goto done; } if (!test_bit(STATUS_READY, &priv->status)) { IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); goto done; } if (!priv->scan_bands) { IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); goto done; } if (!priv->scan) { priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE, GFP_KERNEL); if (!priv->scan) { ret = -ENOMEM; goto done; } } scan = priv->scan; memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; if (iwl_is_associated(priv)) { u16 interval = 0; u32 extra; u32 suspend_time = 100; u32 scan_suspend_time = 100; unsigned long flags; IWL_DEBUG_INFO("Scanning while associated...\n"); spin_lock_irqsave(&priv->lock, flags); interval = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); scan->suspend_time = 0; scan->max_out_time = cpu_to_le32(200 * 1024); if (!interval) interval = suspend_time; extra = (suspend_time / interval) << 22; scan_suspend_time = (extra | ((suspend_time % interval) * 1024)); scan->suspend_time = cpu_to_le32(scan_suspend_time); IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", scan_suspend_time, interval); } /* We should add the ability for user to lock to PASSIVE ONLY */ if (priv->one_direct_scan) { IWL_DEBUG_SCAN("Start direct scan for '%s'\n", iwl_escape_essid(priv->direct_ssid, priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; } else if (!iwl_is_associated(priv) && priv->essid_len) { IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", iwl_escape_essid(priv->essid, priv->essid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); n_probes++; } else { IWL_DEBUG_SCAN("Start indirect scan.\n"); } scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { band = IEEE80211_BAND_2GHZ; scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; tx_ant = iwl_scan_tx_ant(priv, band); if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, tx_ant); else scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, tx_ant | RATE_MCS_CCK_MSK); scan->good_CRC_th = 0; } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { band = IEEE80211_BAND_5GHZ; tx_ant = iwl_scan_tx_ant(priv, band); scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, tx_ant); scan->good_CRC_th = IWL_GOOD_CRC_TH; /* Force use of chains B and C (0x6) for scan Rx for 4965 * Avoid A (0x1) because of its off-channel reception on A-band. * MIMO is not used here, but value is required */ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) rx_chain = 0x6; } else { IWL_WARNING("Invalid scan band count\n"); goto done; } scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); cmd_len = iwl_fill_probe_req(priv, band, (struct ieee80211_mgmt *)scan->data, IWL_MAX_SCAN_SIZE - sizeof(*scan)); scan->tx_cmd.len = cpu_to_le16(cmd_len); if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | RXON_FILTER_BCON_AWARE_MSK); scan->channel_count = iwl_get_channels_for_scan(priv, band, 1, /* active */ n_probes, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); if (scan->channel_count == 0) { IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count); goto done; } cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl_scan_channel); cmd.data = scan; scan->len = cpu_to_le16(cmd.len); set_bit(STATUS_SCAN_HW, &priv->status); ret = iwl_send_cmd_sync(priv, &cmd); if (ret) goto done; queue_delayed_work(priv->workqueue, &priv->scan_check, IWL_SCAN_CHECK_WATCHDOG); mutex_unlock(&priv->mutex); return; done: /* inform mac80211 scan aborted */ queue_work(priv->workqueue, &priv->scan_completed); mutex_unlock(&priv->mutex); } static void iwl_bg_abort_scan(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); if (!iwl_is_ready(priv)) return; mutex_lock(&priv->mutex); set_bit(STATUS_SCAN_ABORTING, &priv->status); iwl_send_scan_abort(priv); mutex_unlock(&priv->mutex); } void iwl_setup_scan_deferred_work(struct iwl_priv *priv) { /* FIXME: move here when resolved PENDING * INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); */ INIT_WORK(&priv->request_scan, iwl_bg_request_scan); INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); }
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { unsigned long flags; struct iwl_priv *priv = hw->priv; int ret; u8 *ssid = NULL; size_t ssid_len = 0; if (req->n_ssids) { ssid = req->ssids[0].ssid; ssid_len = req->ssids[0].ssid_len; } IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->mutex); spin_lock_irqsave(&priv->lock, flags); if (!iwl_is_ready_rf(priv)) { ret = -EIO; IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); goto out_unlock; } /* We don't schedule scan within next_scan_jiffies period. * Avoid scanning during possible EAPOL exchange, return * success immediately. */ if (priv->next_scan_jiffies && time_after(priv->next_scan_jiffies, jiffies)) { IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n"); queue_work(priv->workqueue, &priv->scan_completed); ret = 0; goto out_unlock; } /* if we just finished scan ask for delay */ if (iwl_is_associated(priv) && priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n"); queue_work(priv->workqueue, &priv->scan_completed); ret = 0; goto out_unlock; } if (ssid_len) { priv->one_direct_scan = 1; priv->direct_ssid_len = ssid_len; memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); } else { priv->one_direct_scan = 0; } ret = iwl_scan_initiate(priv); IWL_DEBUG_MAC80211(priv, "leave\n"); out_unlock: spin_unlock_irqrestore(&priv->lock, flags); mutex_unlock(&priv->mutex); return ret; }
/* Called for REPLY_RX (legacy ABG frames), or * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ void iwl_rx_reply_rx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rx_phy_res *phy_res; __le32 rx_pkt_status; struct iwl4965_rx_mpdu_res_start *amsdu; u32 len; u32 ampdu_status; u16 fc; u32 rate_n_flags; /** * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. * REPLY_RX: physical layer info is in this buffer * REPLY_RX_MPDU_CMD: physical layer info was sent in separate * command and cached in priv->last_phy_res * * Here we set up local variables depending on which command is * received. */ if (pkt->hdr.cmd == REPLY_RX) { phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) + phy_res->cfg_phy_cnt); len = le16_to_cpu(phy_res->byte_count); rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + phy_res->cfg_phy_cnt + len); ampdu_status = le32_to_cpu(rx_pkt_status); } else { if (!priv->last_phy_res[0]) { IWL_ERR(priv, "MPDU frame without cached PHY data\n"); return; } phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); len = le16_to_cpu(amsdu->byte_count); rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); ampdu_status = iwl_translate_rx_status(priv, le32_to_cpu(rx_pkt_status)); } if ((unlikely(phy_res->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", phy_res->cfg_phy_cnt); return; } if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", le32_to_cpu(rx_pkt_status)); return; } /* This will be used in several places later */ rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); /* rx_status carries information about the packet to mac80211 */ rx_status.mactime = le64_to_cpu(phy_res->timestamp); rx_status.freq = ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; rx_status.rate_idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); rx_status.flag = 0; /* TSF isn't reliable. In order to allow smooth user experience, * this W/A doesn't propagate it to the mac80211 */ /*rx_status.flag |= RX_FLAG_TSFT;*/ priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); /* Find max signal strength (dBm) among 3 antenna/receiver chains */ rx_status.signal = iwl_calc_rssi(priv, phy_res); /* Meaningful noise values are available only from beacon statistics, * which are gathered only when associated, and indicate noise * only for the associated network channel ... * Ignore these noise values while scanning (other channels) */ if (iwl_is_associated(priv) && !test_bit(STATUS_SCANNING, &priv->status)) { rx_status.noise = priv->last_rx_noise; rx_status.qual = iwl_calc_sig_qual(rx_status.signal, rx_status.noise); } else { rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0); } /* Reset beacon noise level if not associated. */ if (!iwl_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; #ifdef CONFIG_IWLWIFI_DEBUG /* Set "1" to report good data frames in groups of 100 */ if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) iwl_dbg_report_frame(priv, phy_res, len, header, 1); #endif iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.qual, (unsigned long long)rx_status.mactime); /* * "antenna number" * * It seems that the antenna field in the phy flags value * is actually a bit field. This is undefined by radiotap, * it wants an actual antenna number but I always get "7" * for most legacy frames I receive indicating that the * same frame was received on all three RX chains. * * I think this field should be removed in favor of a * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ rx_status.antenna = (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> RX_RES_PHY_FLAGS_ANTENNA_POS; /* set the preamble flag if appropriate */ if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) rx_status.flag |= RX_FLAG_SHORTPRE; /* Set up the HT phy flags */ if (rate_n_flags & RATE_MCS_HT_MSK) rx_status.flag |= RX_FLAG_HT; if (rate_n_flags & RATE_MCS_HT40_MSK) rx_status.flag |= RX_FLAG_40MHZ; if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status.flag |= RX_FLAG_SHORT_GI; if (iwl_is_network_packet(priv, header)) { priv->last_rx_rssi = rx_status.signal; priv->last_beacon_time = priv->ucode_beacon_time; priv->last_tsf = le64_to_cpu(phy_res->timestamp); } fc = le16_to_cpu(header->frame_control); switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: case IEEE80211_FTYPE_DATA: if (priv->iw_mode == NL80211_IFTYPE_AP) iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, header->addr2); /* fall through */ default: iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, rxb, &rx_status); break; } }