📄 iwl4965-base.c
字号:
IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); return -1; } return 0;}/** * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit * @priv: staging_rxon is comapred to active_rxon * * If the RXON structure is changing sufficient to require a new * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 * to indicate a new tune is required. */static int iwl_full_rxon_required(struct iwl_priv *priv){ /* These items are only settable from the full RXON command */ if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) || compare_ether_addr(priv->staging_rxon.bssid_addr, priv->active_rxon.bssid_addr) || compare_ether_addr(priv->staging_rxon.node_addr, priv->active_rxon.node_addr) || compare_ether_addr(priv->staging_rxon.wlap_bssid_addr, priv->active_rxon.wlap_bssid_addr) || (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) || (priv->staging_rxon.channel != priv->active_rxon.channel) || (priv->staging_rxon.air_propagation != priv->active_rxon.air_propagation) || (priv->staging_rxon.ofdm_ht_single_stream_basic_rates != priv->active_rxon.ofdm_ht_single_stream_basic_rates) || (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates != priv->active_rxon.ofdm_ht_dual_stream_basic_rates) || (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) || (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id)) return 1; /* 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 */ if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) != (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)) return 1; /* Check if we are switching association toggle */ if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) != (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) return 1; return 0;}static int iwl_send_rxon_assoc(struct iwl_priv *priv){ int rc = 0; struct iwl_rx_packet *res = NULL; struct iwl_rxon_assoc_cmd rxon_assoc; struct iwl_host_cmd cmd = { .id = REPLY_RXON_ASSOC, .len = sizeof(rxon_assoc), .meta.flags = CMD_WANT_SKB, .data = &rxon_assoc, }; const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; if ((rxon1->flags == rxon2->flags) && (rxon1->filter_flags == rxon2->filter_flags) && (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && (rxon1->ofdm_ht_single_stream_basic_rates == rxon2->ofdm_ht_single_stream_basic_rates) && (rxon1->ofdm_ht_dual_stream_basic_rates == rxon2->ofdm_ht_dual_stream_basic_rates) && (rxon1->rx_chain == rxon2->rx_chain) && (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n"); return 0; } rxon_assoc.flags = priv->staging_rxon.flags; rxon_assoc.filter_flags = priv->staging_rxon.filter_flags; rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates; rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; rxon_assoc.reserved = 0; rxon_assoc.ofdm_ht_single_stream_basic_rates = priv->staging_rxon.ofdm_ht_single_stream_basic_rates; rxon_assoc.ofdm_ht_dual_stream_basic_rates = priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; rc = iwl_send_cmd_sync(priv, &cmd); if (rc) return rc; res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); rc = -EIO; } priv->alloc_rxb_skb--; dev_kfree_skb_any(cmd.meta.u.skb); return rc;}/** * iwl_commit_rxon - commit staging_rxon to hardware * * The RXON command in staging_rxon is commited 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. */static int iwl_commit_rxon(struct iwl_priv *priv){ /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); int rc = 0; if (!iwl_is_alive(priv)) return -1; /* always get timestamp with Rx frame */ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; rc = iwl_check_rxon_cmd(&priv->staging_rxon); if (rc) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } /* 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)) { rc = iwl_send_rxon_assoc(priv); if (rc) { IWL_ERROR("Error setting RXON_ASSOC " "configuration (%d).\n", rc); return rc; } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); return 0; } /* station table will be cleared */ priv->assoc_station_added = 0;#ifdef CONFIG_IWLWIFI_SENSITIVITY priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; if (!priv->error_recovering) priv->start_calib = 0; iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);#endif /* CONFIG_IWLWIFI_SENSITIVITY */ /* If we are currently associated and the new config requires * an RXON_ASSOC and the new config wants the associated mask enabled, * we must clear the associated from the active configuration * before we apply the new config */ if (iwl_is_associated(priv) && (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; rc = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set * active_rxon back to what it was previously */ if (rc) { active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; IWL_ERROR("Error clearing ASSOC_MSK on current " "configuration (%d).\n", rc); return rc; } } IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" "* bssid = %s\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), print_mac(mac, priv->staging_rxon.bssid_addr)); /* Apply the new configuration */ rc = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); if (rc) { IWL_ERROR("Error setting new configuration (%d).\n", rc); return rc; } iwl_clear_stations_table(priv);#ifdef CONFIG_IWLWIFI_SENSITIVITY if (!priv->error_recovering) priv->start_calib = 0; priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);#endif /* CONFIG_IWLWIFI_SENSITIVITY */ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); /* 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 */ rc = iwl_hw_reg_send_txpower(priv); if (rc) { IWL_ERROR("Error setting Tx power (%d).\n", rc); return rc; } /* Add the broadcast address so we can send broadcast frames */ if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; } /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ if (iwl_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); return -EIO; } priv->assoc_station_added = 1; } return 0;}static int iwl_send_bt_config(struct iwl_priv *priv){ struct iwl_bt_cmd bt_cmd = { .flags = 3, .lead_time = 0xAA, .max_kill = 1, .kill_ack_mask = 0, .kill_cts_mask = 0, }; return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(struct iwl_bt_cmd), &bt_cmd);}static int iwl_send_scan_abort(struct iwl_priv *priv){ int rc = 0; struct iwl_rx_packet *res; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .meta.flags = CMD_WANT_SKB, }; /* If there isn't a scan actively going on in the hardware * then we are in between scan bands and not actually * actively scanning, so don't send the abort command */ if (!test_bit(STATUS_SCAN_HW, &priv->status)) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return 0; } rc = iwl_send_cmd_sync(priv, &cmd); if (rc) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return rc; } res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); } dev_kfree_skb_any(cmd.meta.u.skb); return rc;}static int iwl_card_state_sync_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb){ return 1;}/* * CARD_STATE_CMD * * Use: Sets the internal card state to enable, disable, or halt * * When in the 'enable' state the card operates as normal. * When in the 'disable' state, the card enters into a low power mode. * When in the 'halt' state, the card is shut down and must be fully * restarted to come back on. */static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag){ struct iwl_host_cmd cmd = { .id = REPLY_CARD_STATE_CMD, .len = sizeof(u32), .data = &flags, .meta.flags = meta_flag, }; if (meta_flag & CMD_ASYNC) cmd.meta.u.callback = iwl_card_state_sync_callback; return iwl_send_cmd(priv, &cmd);}static int iwl_add_sta_sync_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb){ struct iwl_rx_packet *res = NULL; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); return 1; } res = (struct iwl_rx_packet *)skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); return 1; } switch (res->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: break; default: break; } /* We didn't cache the SKB; let the caller free it */ return 1;}int iwl_send_add_station(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags){ struct iwl_rx_packet *res = NULL; int rc = 0; struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, .len = sizeof(struct iwl_addsta_cmd), .meta.flags = flags, .data = sta, }; if (flags & CMD_ASYNC) cmd.meta.u.callback = iwl_add_sta_sync_callback; else cmd.meta.flags |= CMD_WANT_SKB; rc = iwl_send_cmd(priv, &cmd); if (rc || (flags & CMD_ASYNC)) return rc; res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); rc = -EIO; } if (rc == 0) { switch (res->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); break; default: rc = -EIO; IWL_WARNING("REPLY_ADD_STA failed\n"); break; } } priv->alloc_rxb_skb--; dev_kfree_skb_any(cmd.meta.u.skb); return rc;}static int iwl_update_sta_key_info(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id){ unsigned long flags; __le16 key_flags = 0; switch (keyconf->alg) { case ALG_CCMP: key_flags |= STA_KEY_FLG_CCMP; key_flags |= cpu_to_le16( keyconf->keyidx << STA_KEY_FLG_KEYID_POS); key_flags &= ~STA_KEY_FLG_INVALID; break; case ALG_TKIP: case ALG_WEP: return -EINVAL; default: return -EINVAL; } spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].keyinfo.alg = keyconf->alg; priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, keyconf->keylen); memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, keyconf->keylen); priv->stations[sta_id].sta.key.key_flags = key_flags; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); return 0;}static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id){ unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo)); priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); return 0;}static void iwl_clear_free_frames(struct iwl_priv *priv){ struct list_head *element; IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n", priv->frames_count); while (!list_empty(&priv->free_frames)) { element = priv->free_frames.next; list_del(element); kfree(list_entry(element, struct iwl_frame, list)); priv->frames_count--; } if (priv->frames_count) { IWL_WARNING("%d frames still in use. Did we lose one?\n", priv->frames_count); priv->frames_count = 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -