case NL80211_IFTYPE_MONITOR:
ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER; break;
default:
IWL_ERR(priv, "Unsupported interface type %d\n",
ctx->vif->type); break;
}
#if 0 /* TODO: Figure out when short_preamble would be set and cache from
* that */ if (!hw_to_local(priv->hw)->short_preamble)
ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; else
ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif
/* clear both MIX and PURE40 mode flag */
ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
RXON_FLG_CHANNEL_MODE_PURE_40); if (ctx->vif)
memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
if (ret) {
IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
iwl_remove_notification(&priv->notif_wait, &disable_wait);
} else {
ret = iwl_wait_notification(&priv->notif_wait,
&disable_wait, HZ); if (ret)
IWL_ERR(priv, "Timed out waiting for PAN disable\n");
}
/* * If mac80211 hasn't given us a beacon interval, program * the default into the device (not checking this here * would cause the adjustment below to return the maximum * value, which may break PAN.)
*/ if (!beacon_val) return DEFAULT_BEACON_INTERVAL;
/* * If the beacon interval we obtained from the peer * is too large, we'll have to wake up more often * (and in IBSS case, we'll beacon too much) * * For example, if max_beacon_val is 4096, and the * requested beacon interval is 7000, we'll have to * use 3500 to be able to wake up on the beacons. * * This could badly influence beacon detection stats.
*/
if (ctx->ctxid == IWL_RXON_CTX_BSS) {
ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
} else {
ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); if (ret) return ret; if (ctx->vif) {
ret = iwl_send_rxon_timing(priv, ctx); if (ret) {
IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); return ret;
}
ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
}
} if (ret) return ret;
/* * Un-assoc RXON clears the station table and WEP * keys, so we have to restore those afterwards.
*/
iwl_clear_ucode_stations(priv, ctx); /* update -- might need P2P now */
iwl_update_bcast_station(priv, ctx);
iwl_restore_stations(priv, ctx);
ret = iwl_restore_default_wep_keys(priv, ctx); if (ret) {
IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); return ret;
}
if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED) return 0;
lockdep_assert_held(&priv->mutex);
if (priv->tx_power_user_lmt == tx_power && !force) return 0;
if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n",
tx_power,
IWLAGN_TX_POWER_TARGET_POWER_MIN); return -EINVAL;
}
if (tx_power > DIV_ROUND_UP(priv->nvm_data->max_tx_pwr_half_dbm, 2)) {
IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n",
tx_power, priv->nvm_data->max_tx_pwr_half_dbm); return -EINVAL;
}
if (!iwl_is_ready_rf(priv)) return -EIO;
/* scan complete and commit_rxon use tx_power_next value,
* it always need to be updated for newest request */
priv->tx_power_next = tx_power;
/* do not set tx power when scanning or channel changing */
defer = test_bit(STATUS_SCANNING, &priv->status) ||
memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); if (defer && !force) {
IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); return 0;
}
/* if fail to set tx_power, restore the orig. tx power */ if (ret) {
priv->tx_power_user_lmt = prev_tx_power;
priv->tx_power_next = prev_tx_power;
} return ret;
}
/* RXON timing must be before associated RXON */ if (ctx->ctxid == IWL_RXON_CTX_BSS) {
ret = iwl_send_rxon_timing(priv, ctx); if (ret) {
IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); return ret;
}
} /* QoS info may be cleared by previous un-assoc RXON */
iwlagn_update_qos(priv, ctx);
/* * We'll run into this code path when beaconing is * enabled, but then we also need to send the beacon * to the device.
*/ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
ret = iwlagn_update_beacon(priv, ctx->vif); if (ret) {
IWL_ERR(priv, "Error sending required beacon (%d)!\n",
ret); return ret;
}
}
priv->start_calib = 0; /* * Apply the new configuration. * * Associated RXON doesn't clear the station table in uCode, * so we don't need to restore stations etc. after this.
*/
ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, 0, sizeof(struct iwl_rxon_cmd), &ctx->staging); if (ret) {
IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); return ret;
}
memcpy(active, &ctx->staging, sizeof(*active));
/* IBSS beacon needs to be sent after setting assoc */ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) if (iwlagn_update_beacon(priv, ctx->vif))
IWL_ERR(priv, "Error sending IBSS beacon\n");
iwl_init_sensitivity(priv);
/* * If we issue a new RXON command which required a tune then * we must send a new TXPOWER command or we won't be able to * Tx any frames. * * It's expected we set power here if channel is changing.
*/
ret = iwl_set_tx_power(priv, priv->tx_power_next, true); if (ret) {
IWL_ERR(priv, "Error sending TX power (%d)\n", ret); return ret;
}
return 0;
}
int iwlagn_set_pan_params(struct iwl_priv *priv)
{ struct iwl_wipan_params_cmd cmd; struct iwl_rxon_context *ctx_bss, *ctx_pan; int slot0 = 300, slot1 = 0; int ret;
if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS)) return 0;
/* * If the PAN context is inactive, then we don't need * to update the PAN parameters, the last thing we'll * have done before it goes inactive is making the PAN * parameters be WLAN-only.
*/ if (!ctx_pan->is_active) return 0;
memset(&cmd, 0, sizeof(cmd));
/* only 2 slots are currently allowed */
cmd.num_slots = 2;
/* FIXME: if the definition of ht.protection changed, the "translation" * will be needed for rxon->flags
*/
rxon->flags |= cpu_to_le32(ctx->ht.protection <<
RXON_FLG_HT_OPERATING_MODE_POS);
/* Set up channel bandwidth:
* 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ /* clear the HT channel mode before set the mode */
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) { /* pure ht40 */ if (ctx->ht.protection ==
IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; /* * Note: control channel is opposite of extension * channel
*/ switch (ctx->ht.extension_chan_offset) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &=
~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
rxon->flags |=
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break;
}
} else { /* * Note: control channel is opposite of extension * channel
*/ switch (ctx->ht.extension_chan_offset) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &=
~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; break; case IEEE80211_HT_PARAM_CHA_SEC_NONE: default: /* * channel location only valid if in Mixed * mode
*/
IWL_ERR(priv, "invalid extension channel offset\n"); break;
}
}
} else {
rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
}
/* * iwl_set_rxon_channel - Set the band and channel values in staging RXON * @ch: requested channel as a pointer to struct ieee80211_channel
* NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the ch->band
*/ void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, struct iwl_rxon_context *ctx)
{ enum nl80211_band band = ch->band;
u16 channel = ch->hw_value;
if ((le16_to_cpu(ctx->staging.channel) == channel) &&
(priv->band == band)) return;
/* * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * @priv: staging_rxon is compared to active_rxon * * If the RXON structure is changing enough to require a new tune, * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
*/ staticint iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{ conststruct iwl_rxon_cmd *staging = &ctx->staging; conststruct iwl_rxon_cmd *active = &ctx->active;
#define CHK(cond) \ if ((cond)) { \
IWL_DEBUG_INFO(priv, "need full RXON - "#cond"\n"); \ return 1; \
}
/* These items are only settable from the full RXON command */
CHK(!iwl_is_associated_ctx(ctx));
CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr));
CHK(!ether_addr_equal(staging->node_addr, active->node_addr));
CHK(!ether_addr_equal(staging->wlap_bssid_addr,
active->wlap_bssid_addr));
CHK_NEQ(staging->dev_type, active->dev_type);
CHK_NEQ(staging->channel, active->channel);
CHK_NEQ(staging->air_propagation, active->air_propagation);
CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
active->ofdm_ht_single_stream_basic_rates);
CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
active->ofdm_ht_dual_stream_basic_rates);
CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
active->ofdm_ht_triple_stream_basic_rates);
CHK_NEQ(staging->assoc_id, active->assoc_id);
/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can * be updated with the RXON_ASSOC command -- however only some
* flag transitions are allowed using RXON_ASSOC */
/* Check if we are not switching bands */
CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
active->flags & RXON_FLG_BAND_24G_MSK);
/* Check if we are switching association toggle */
CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
active->filter_flags & RXON_FILTER_ASSOC_MSK);
/* * Now we've got the basic rates as bitmaps in the ofdm and cck * variables. This isn't sufficient though, as there might not * be all the right rates in the bitmap. E.g. if the only basic * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps * and 6 Mbps because the 802.11-2007 standard says in 9.6: * * [...] a STA responding to a received frame shall transmit * its Control Response frame [...] at the highest rate in the * BSSBasicRateSet parameter that is less than or equal to the * rate of the immediately previous frame in the frame exchange * sequence ([...]) and that is of the same modulation class * ([...]) as the received frame. If no rate contained in the * BSSBasicRateSet parameter meets these conditions, then the * control frame sent in response to a received frame shall be * transmitted at the highest mandatory rate of the PHY that is * less than or equal to the rate of the received frame, and * that is of the same modulation class as the received frame. * * As a consequence, we need to add all mandatory rates that are * lower than all of the basic rates to these bitmaps.
*/
if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE; if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE; /* 6M already there or needed so always add */
ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE;
/* * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. * Note, however: * - if no CCK rates are basic, it must be ERP since there must * be some basic rates at all, so they're OFDM => ERP PHY * (or we're in 5 GHz, and the cck bitmap will never be used) * - if 11M is a basic rate, it must be ERP as well, so add 5.5M * - if 5.5M is basic, 1M and 2M are mandatory * - if 2M is basic, 1M is mandatory * - if 1M is basic, that's the only valid ACK rate. * As a consequence, it's not as complicated as it sounds, just add * any lower rates to the ACK rate bitmap.
*/ if (IWL_RATE_11M_INDEX < lowest_present_cck)
cck |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE; if (IWL_RATE_5M_INDEX < lowest_present_cck)
cck |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE; if (IWL_RATE_2M_INDEX < lowest_present_cck)
cck |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE; /* 1M already there or needed so always add */
cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
/* "basic_rates" is a misnomer here -- should be called ACK rates */
ctx->staging.cck_basic_rates = cck;
ctx->staging.ofdm_basic_rates = ofdm;
}
/* * iwlagn_commit_rxon - commit staging_rxon to hardware * * The RXON command in staging_rxon is committed to the hardware and * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. * * The connect/disconnect flow should be as the following: * * 1. make sure send RXON command with association bit unset if not connect * this should include the channel and the band for the candidate * to be connected to * 2. Add Station before RXON association with the AP * 3. RXON_timing has to send before RXON for connection * 4. full RXON command - associated bit set * 5. use RXON_ASSOC command to update any flags changes
*/ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{ /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active = (void *)(uintptr_t)&ctx->active; bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); int ret;
lockdep_assert_held(&priv->mutex);
if (!iwl_is_alive(priv)) return -EBUSY;
/* This function hardcodes a bunch of dual-mode assumptions */
BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
if (!ctx->is_active) return 0;
/* always get timestamp with Rx frame */
ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
/* * force CTS-to-self frames protection if RTS-CTS is not preferred * one aggregation protection method
*/ if (!priv->hw_params.use_rts_for_aggregation)
ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
iwl_print_rx_config_cmd(priv, ctx->ctxid);
ret = iwl_check_rxon_cmd(priv, ctx); if (ret) {
IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); return -EINVAL;
}
/* * receive commit_rxon request * abort any previous channel switch if still in process
*/ if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
(priv->switch_channel != ctx->staging.channel)) {
IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
le16_to_cpu(priv->switch_channel));
iwl_chswitch_done(priv, false);
}
/* * If we don't need to send a full RXON, we can use * iwl_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration.
*/ if (!iwl_full_rxon_required(priv, ctx)) {
ret = iwlagn_send_rxon_assoc(priv, ctx); if (ret) {
IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); return ret;
}
memcpy(active, &ctx->staging, sizeof(*active)); /* * We do not commit tx power settings while channel changing, * do it now if after settings changed.
*/
iwl_set_tx_power(priv, priv->tx_power_next, false);
/* make sure we are in the right PS state */
iwl_power_update_mode(priv, true);
/* * Always clear associated first, but with the correct config. * This is required as for example station addition for the * AP station must be done after the BSSID is set to correctly * set up filters in the device.
*/
ret = iwlagn_rxon_disconn(priv, ctx); if (ret) return ret;
ret = iwlagn_set_pan_params(priv); if (ret) return ret;
if (new_assoc) return iwlagn_rxon_connect(priv, ctx);
if (!iwl_is_ready(priv)) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out;
}
if (changed & (IEEE80211_CONF_CHANGE_SMPS |
IEEE80211_CONF_CHANGE_CHANNEL)) { /* mac80211 uses static for non-HT which is what we want */
priv->current_ht_config.smps = conf->smps_mode;
/* * Recalculate chain counts. * * If monitor mode is enabled then mac80211 will * set up the SM PS mode to OFF if an HT channel is * configured.
*/
for_each_context(priv, ctx)
iwlagn_set_rxon_chain(priv, ctx);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
for_each_context(priv, ctx) { /* Configure HT40 channels */ if (ctx->ht.enabled != conf_is_ht(conf))
ctx->ht.enabled = conf_is_ht(conf);
if (ctx->ht.enabled) { /* if HT40 is used, it should not change
* after associated except channel switch */ if (!ctx->ht.is_40mhz ||
!iwl_is_associated_ctx(ctx))
iwlagn_config_ht40(conf, ctx);
} else
ctx->ht.is_40mhz = false;
/* * Default to no protection. Protection mode will * later be set from BSS config in iwl_ht_conf
*/
ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
/* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not
* support ht */ if (le16_to_cpu(ctx->staging.channel) !=
channel->hw_value)
ctx->staging.flags = 0;
switch (vif->type) { case NL80211_IFTYPE_STATION:
rcu_read_lock();
sta = ieee80211_find_sta(vif, bss_conf->bssid); if (!sta) { /* * If at all, this can only happen through a race * when the AP disconnects us while we're still * setting up the connection, in that case mac80211 * will soon tell us about that.
*/
need_multiple = false;
rcu_read_unlock(); break;
}
ht_cap = &sta->deflink.ht_cap;
need_multiple = true;
/* * If the peer advertises no support for receiving 2 and 3 * stream MCS rates, it can't be transmitting them either.
*/ if (ht_cap->mcs.rx_mask[1] == 0 &&
ht_cap->mcs.rx_mask[2] == 0) {
need_multiple = false;
} elseif (!(ht_cap->mcs.tx_params &
IEEE80211_HT_MCS_TX_DEFINED)) { /* If it can't TX MCS at all ... */
need_multiple = false;
} elseif (ht_cap->mcs.tx_params &
IEEE80211_HT_MCS_TX_RX_DIFF) { int maxstreams;
/* * But if it can receive them, it might still not * be able to transmit them, which is what we need * to check here -- so check the number of streams * it advertises for TX (if different from RX).
*/
if (changes & BSS_CHANGED_IDLE && vif->cfg.idle) { /* * If we go idle, then clearly no "passive-no-rx" * workaround is needed any more, this is a reset.
*/
iwlagn_lift_passive_no_rx(priv);
}
if (unlikely(!iwl_is_ready(priv))) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
mutex_unlock(&priv->mutex); return;
}
if (unlikely(!ctx->vif)) {
IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
mutex_unlock(&priv->mutex); return;
}
if (changes & BSS_CHANGED_BEACON_INT)
force = true;
/* * If the ucode decides to do beacon filtering before * association, it will lose beacons that are needed * before sending frames out on passive channels. This * causes association failures on those channels. Enable * receiving beacons in such cases.
*/
if (vif->type == NL80211_IFTYPE_STATION) { if (!vif->cfg.assoc)
ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK; else
ctx->staging.filter_flags &=
~RXON_FILTER_BCON_AWARE_MSK;
}
if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
iwlagn_commit_rxon(priv, ctx);
if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) { /* * The chain noise calibration will enable PM upon * completion. If calibration has already been run * then we need to enable power management here.
*/ if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
iwl_power_update_mode(priv, false);
/* Enable RX differential gain and sensitivity calibrations */
iwlagn_chain_noise_reset(priv);
priv->start_calib = 1;
}
if (changes & BSS_CHANGED_IBSS) {
ret = iwlagn_manage_ibss_station(priv, vif,
vif->cfg.ibss_joined); if (ret)
IWL_ERR(priv, "failed to %s IBSS station %pM\n",
vif->cfg.ibss_joined ? "add" : "remove",
bss_conf->bssid);
}
if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) { if (iwlagn_update_beacon(priv, vif))
IWL_ERR(priv, "Error updating beacon\n");
}
/* * We do not commit power settings while scan is pending, * do it now if the settings changed.
*/
iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
iwl_set_tx_power(priv, priv->tx_power_next, false);
/* * Since setting the RXON may have been deferred while * performing the scan, fire one off if needed
*/
for_each_context(priv, ctx) if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
iwlagn_commit_rxon(priv, ctx);
iwlagn_set_pan_params(priv);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.