/* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here.
*/ int iwlagn_mac_setup_register(struct iwl_priv *priv, conststruct iwl_ucode_capabilities *capa)
{ int ret; struct ieee80211_hw *hw = priv->hw; struct iwl_rxon_context *ctx;
/* * Including the following line will crash some AP's. This * workaround removes the stimulus which causes the crash until * the AP software can be fixed. hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
*/
if (priv->nvm_data->sku_cap_11n_enable)
hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
NL80211_FEATURE_STATIC_SMPS;
/* * Enable 11w if advertised by firmware and software crypto * is not enabled (as the firmware will interpret some mgmt * packets, so enabling it with software crypto isn't safe)
*/ if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
!iwlwifi_mod_params.swcrypto)
ieee80211_hw_set(hw, MFP_CAPABLE);
if (iwlwifi_mod_params.power_save)
hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; else
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a max-length SSID element */
hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
/* * We don't use all queues: 4 and 9 are unused and any * aggregation queue gets mapped down to the AC queue.
*/
hw->queues = IWLAGN_FIRST_AMPDU_QUEUE;
if (priv->nvm_data->bands[NL80211_BAND_2GHZ].n_channels)
priv->hw->wiphy->bands[NL80211_BAND_2GHZ] =
&priv->nvm_data->bands[NL80211_BAND_2GHZ]; if (priv->nvm_data->bands[NL80211_BAND_5GHZ].n_channels)
priv->hw->wiphy->bands[NL80211_BAND_5GHZ] =
&priv->nvm_data->bands[NL80211_BAND_5GHZ];
/* we should be verifying the device is ready to be opened */
mutex_lock(&priv->mutex);
ret = __iwl_up(priv);
mutex_unlock(&priv->mutex); if (ret) return ret;
IWL_DEBUG_INFO(priv, "Start UP work done.\n");
/* Now we should be done, and the READY bit should be set. */ if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
ret = -EIO;
/* we'll clear ctx->vif during iwlagn_prepare_restart() */
vif = ctx->vif;
ret = iwl_trans_d3_resume(priv->trans, &d3_status, false, true); if (ret) goto out_unlock;
if (d3_status != IWL_D3_STATUS_ALIVE) {
IWL_INFO(priv, "Device was reset during suspend\n"); goto out_unlock;
}
/* uCode is no longer operating by itself */
iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
base = priv->device_pointers.error_event_table; if (!iwlagn_hw_valid_rtc_data_addr(base)) {
IWL_WARN(priv, "Invalid error table during resume!\n"); goto out_unlock;
}
if (priv->wowlan_sram)
iwl_trans_read_mem(priv->trans, 0x800000,
priv->wowlan_sram,
img->sec[IWL_UCODE_SECTION_DATA].len / 4); #endif
/* * This is very strange. The GET_STATUS command is sent but the device * doesn't reply properly, it seems it doesn't close the RBD so one is * always left open ... As a result, we need to send another command * and have to reset the driver afterwards. As we need to switch to * runtime firmware again that'll happen.
*/
iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_GET_STATUS, CMD_ASYNC, 0, NULL);
iwl_dvm_send_cmd_pdu(priv, REPLY_ECHO, CMD_ASYNC, 0, NULL); /* an RBD is left open in the firmware now! */
ret = iwl_wait_notification(&priv->notif_wait, &status_wait, HZ/5); if (ret) goto out_unlock;
switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP:
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
fallthrough; case WLAN_CIPHER_SUITE_CCMP:
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; default: break;
}
/* * We could program these keys into the hardware as well, but we * don't expect much multicast traffic in IBSS and having keys * for more stations is probably more useful. * * Mark key TX-only and return 0.
*/ if (vif->type == NL80211_IFTYPE_ADHOC &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
key->hw_key_idx = WEP_INVALID_OFFSET; return 0;
}
/* If they key was TX-only, accept deletion */ if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET) return 0;
/* * If we are getting WEP group key and we didn't receive any key mapping * so far, we are in legacy wep mode (group key only), otherwise we are * in 1X mode. * In legacy wep mode, we use another host command to the uCode.
*/ if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) { if (cmd == SET_KEY)
is_default_wep_key = !ctx->key_mapping_keys; else
is_default_wep_key =
key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
}
switch (cmd) { case SET_KEY: if (is_default_wep_key) {
ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key); break;
}
ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta); if (ret) { /* * can't add key for RX, but we don't need it * in the device for TX so still return 0
*/
ret = 0;
key->hw_key_idx = WEP_INVALID_OFFSET;
}
IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n"); break; case DISABLE_KEY: if (is_default_wep_key)
ret = iwl_remove_default_wep_key(priv, ctx, key); else
ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n"); break; default:
ret = -EINVAL;
}
IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
sta->addr);
sta_priv->sta_id = IWL_INVALID_STATION;
atomic_set(&sta_priv->pending_frames, 0); if (vif->type == NL80211_IFTYPE_AP)
sta_priv->client = true;
ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
is_ap, sta, &sta_id); if (ret) {
IWL_ERR(priv, "Unable to add station %pM (%d)\n",
sta->addr, ret); /* Should we return success if return code is EEXIST ? */ return ret;
}
IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", sta->addr);
if (vif->type == NL80211_IFTYPE_STATION) { /* * Station will be removed from device when the RXON * is set to unassociated -- just deactivate it here * to avoid re-programming it.
*/
ret = 0;
iwl_deactivate_station(priv, sta_priv->sta_id, sta->addr);
} else {
ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr); if (ret)
IWL_DEBUG_QUIET_RFKILL(priv, "Error removing station %pM\n", sta->addr);
} return ret;
}
IWL_DEBUG_MAC80211(priv, "station %pM state change %d->%d\n",
sta->addr, old_state, new_state);
mutex_lock(&priv->mutex); if (vif->type == NL80211_IFTYPE_STATION) { if (old_state == IEEE80211_STA_NOTEXIST &&
new_state == IEEE80211_STA_NONE)
op = ADD; elseif (old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)
op = REMOVE; elseif (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC)
op = HT_RATE_INIT;
} else { if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC)
op = ADD_RATE_INIT; elseif (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH)
op = REMOVE;
}
switch (op) { case ADD:
ret = iwlagn_mac_sta_add(hw, vif, sta); if (ret) break; /* * Clear the in-progress flag, the AP station entry was added * but we'll initialize LQ only when we've associated (which * would also clear the in-progress flag). This is necessary * in case we never initialize LQ because association fails.
*/
spin_lock_bh(&priv->sta_lock);
priv->stations[iwl_sta_id(sta)].used &=
~IWL_STA_UCODE_INPROGRESS;
spin_unlock_bh(&priv->sta_lock); break; case REMOVE:
ret = iwlagn_mac_sta_remove(hw, vif, sta); break; case ADD_RATE_INIT:
ret = iwlagn_mac_sta_add(hw, vif, sta); if (ret) break; /* Initialize rate scaling */
IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
sta->addr);
iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
ret = 0; break; case HT_RATE_INIT: /* Initialize rate scaling */
ret = iwl_sta_update_ht(priv, vif_priv->ctx, sta); if (ret) break;
IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
sta->addr);
iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
ret = 0; break; default:
ret = 0; break;
}
/* * mac80211 might WARN if we fail, but due the way we * (badly) handle hard rfkill, we might fail here
*/ if (iwl_is_rfkill(priv))
ret = 0;
staticvoid iwlagn_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *ch_switch)
{ struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct ieee80211_conf *conf = &hw->conf; struct ieee80211_channel *channel = ch_switch->chandef.chan; struct iwl_ht_config *ht_conf = &priv->current_ht_config; /* * MULTI-FIXME * When we add support for multiple interfaces, we need to * revisit this. The channel switch command in the device * only affects the BSS context, but what does that really * mean? And what if we get a CSA on the second interface? * This needs a lot of work.
*/ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
u16 ch;
/* * at this point, staging_rxon has the * configuration for channel switch
*/
set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
priv->switch_channel = cpu_to_le16(ch); if (priv->lib->set_channel_switch(priv, ch_switch)) {
clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
priv->switch_channel = 0;
ieee80211_chswitch_done(ctx->vif, false, 0);
}
/* * Not committing directly because hardware can perform a scan, * but we'll eventually commit the filter flags change anyway.
*/
}
mutex_unlock(&priv->mutex);
/* * Receiving all multicast frames is always enabled by the * default flags setup in iwl_connection_init_rx_config() * since we currently do not support programming multicast * filters into the device.
*/
*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n"); goto done;
} if (iwl_is_rfkill(priv)) {
IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n"); goto done;
}
/* * This variable will be correct only when there's just * a single context, but all code using it is for hardware * that supports only one context.
*/
priv->iw_mode = vif->type;
ctx->is_active = true;
err = iwl_set_mode(priv, ctx); if (err) { if (!ctx->always_active)
ctx->is_active = false; return err;
}
if (priv->lib->bt_params && priv->lib->bt_params->advanced_bt_coexist &&
vif->type == NL80211_IFTYPE_ADHOC) { /* * pretend to have high BT traffic as long as we * are operating in IBSS mode, as this will cause * the rate scaling etc. to behave as intended.
*/
priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
}
/* set up queue mappings */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
vif->hw_queue[ac] = ctx->ac_to_queue[ac];
/* * In SNIFFER device type, the firmware reports the FCS to * the host, rather than snipping it off. Unfortunately, * mac80211 doesn't (yet) provide a per-packet flag for * this, so that we have to set the hardware flag based * on the interfaces added. As the monitor interface can * only be present by itself, and will be removed before * other interfaces are added, this is safe.
*/ if (vif->type == NL80211_IFTYPE_MONITOR)
ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS); else
__clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, priv->hw->flags);
err = iwl_setup_interface(priv, ctx); if (!err || reset) goto out;
if (priv->scan_vif == vif) {
iwl_scan_cancel_timeout(priv, 200);
iwl_force_scan_end(priv);
}
if (!mode_change) {
iwl_set_mode(priv, ctx); if (!ctx->always_active)
ctx->is_active = false;
}
/* * When removing the IBSS interface, overwrite the * BT traffic load with the stored one from the last * notification, if any. If this is a device that * doesn't implement this, this has no effect since * both values are the same and zero.
*/ if (vif->type == NL80211_IFTYPE_ADHOC)
priv->bt_traffic_load = priv->last_bt_traffic_load;
}
/* * To simplify this code, only support changes on the * BSS context. The PAN context is usually reassigned * by creating/removing P2P interfaces anyway.
*/ if (ctx->ctxid != IWL_RXON_CTX_BSS) {
err = -EBUSY; goto out;
}
if (!ctx->vif || !iwl_is_ready_rf(priv)) { /* * Huh? But wait ... this can maybe happen when * we're in the middle of a firmware restart!
*/
err = -EBUSY; goto out;
}
/* Check if the switch is supported in the same context */
interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; if (!(interface_modes & BIT(newtype))) {
err = -EBUSY; goto out;
}
if (ctx->exclusive_interface_modes & BIT(newtype)) {
for_each_context(priv, tmp) { if (ctx == tmp) continue;
if (!tmp->is_active) continue;
/* * The current mode switch would be exclusive, but * another context is active ... refuse the switch.
*/
err = -EBUSY; goto out;
}
}
/* success */
iwl_teardown_interface(priv, vif, true);
vif->type = newviftype;
vif->p2p = newp2p;
err = iwl_setup_interface(priv, ctx);
WARN_ON(err); /* * We've switched internally, but submitting to the * device may have failed for some reason. Mask this * error, because otherwise mac80211 will not switch * (and set the interface type back) and we'll be * out of sync with it.
*/
err = 0;
/* * If an internal scan is in progress, just set * up the scan_request as per above.
*/ if (priv->scan_type != IWL_SCAN_NORMAL) {
IWL_DEBUG_SCAN(priv, "SCAN request during internal scan - defer\n");
priv->scan_request = req;
priv->scan_vif = vif;
ret = 0;
} else {
priv->scan_request = req;
priv->scan_vif = vif; /* * mac80211 will only ask for one band at a time * so using channels[0] here is ok
*/
ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
req->channels[0]->band); if (ret) {
priv->scan_request = NULL;
priv->scan_vif = NULL;
}
}
/* This function both allocates and initializes hw and priv. */ struct ieee80211_hw *iwl_alloc_all(void)
{ struct iwl_priv *priv; struct iwl_op_mode *op_mode; /* mac80211 allocates memory for this device instance, including
* space for this driver's private structure */ struct ieee80211_hw *hw;
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.