⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iwl4965-base.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -