diff options
30 files changed, 210 insertions, 91 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6ceb2e18808..caf572cf270 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1967,7 +1967,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)  	}  	/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ -	REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); +	if (AR_SREV_9300_20_OR_LATER(ah)) +		REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);  }  /* diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index bc9bbbb2b49..8d3bad7ea5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -182,6 +182,7 @@ static struct iwl_base_params iwl1000_base_params = {  	.chain_noise_scale = 1000,  	.wd_timeout = IWL_DEF_WD_TIMEOUT,  	.max_event_log_size = 128, +	.wd_disable = true,  };  static struct iwl_ht_params iwl1000_ht_params = {  	.ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3a3f8303238..cf2fb47529b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -350,6 +350,7 @@ static struct iwl_base_params iwl5000_base_params = {  	.wd_timeout = IWL_LONG_WD_TIMEOUT,  	.max_event_log_size = 512,  	.no_idle_support = true, +	.wd_disable = true,  };  static struct iwl_ht_params iwl5000_ht_params = {  	.ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 8de97f5a182..00b38711c15 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -529,6 +529,24 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)  	return 0;  } +void iwlagn_config_ht40(struct ieee80211_conf *conf, +	struct iwl_rxon_context *ctx) +{ +	if (conf_is_ht40_minus(conf)) { +		ctx->ht.extension_chan_offset = +			IEEE80211_HT_PARAM_CHA_SEC_BELOW; +		ctx->ht.is_40mhz = true; +	} else if (conf_is_ht40_plus(conf)) { +		ctx->ht.extension_chan_offset = +			IEEE80211_HT_PARAM_CHA_SEC_ABOVE; +		ctx->ht.is_40mhz = true; +	} else { +		ctx->ht.extension_chan_offset = +			IEEE80211_HT_PARAM_CHA_SEC_NONE; +		ctx->ht.is_40mhz = false; +	} +} +  int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)  {  	struct iwl_priv *priv = hw->priv; @@ -590,19 +608,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)  				ctx->ht.enabled = conf_is_ht(conf);  			if (ctx->ht.enabled) { -				if (conf_is_ht40_minus(conf)) { -					ctx->ht.extension_chan_offset = -						IEEE80211_HT_PARAM_CHA_SEC_BELOW; -					ctx->ht.is_40mhz = true; -				} else if (conf_is_ht40_plus(conf)) { -					ctx->ht.extension_chan_offset = -						IEEE80211_HT_PARAM_CHA_SEC_ABOVE; -					ctx->ht.is_40mhz = true; -				} else { -					ctx->ht.extension_chan_offset = -						IEEE80211_HT_PARAM_CHA_SEC_NONE; -					ctx->ht.is_40mhz = false; -				} +				/* if HT40 is used, it should not change +				 * after associated except channel switch */ +				if (iwl_is_associated_ctx(ctx) && +				     !ctx->ht.is_40mhz) +					iwlagn_config_ht40(conf, ctx);  			} else  				ctx->ht.is_40mhz = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 901fd9485d7..626ed701100 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1250,9 +1250,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,  	switch (keyconf->cipher) {  	case WLAN_CIPHER_SUITE_TKIP: -		keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; -		keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; -  		if (sta)  			addr = sta->addr;  		else /* station mode case only */ @@ -1265,8 +1262,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,  					  seq.tkip.iv32, p1k, CMD_SYNC);  		break;  	case WLAN_CIPHER_SUITE_CCMP: -		keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; -		/* fall through */  	case WLAN_CIPHER_SUITE_WEP40:  	case WLAN_CIPHER_SUITE_WEP104:  		ret = iwlagn_send_sta_key(priv, keyconf, sta_id, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index db0d3a84b1e..4d20be9dea3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2022,9 +2022,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])");  module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);  MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); -module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO); +module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO);  MODULE_PARM_DESC(wd_disable, -		"Disable stuck queue watchdog timer (default: 0 [enabled])"); +		"Disable stuck queue watchdog timer 0=system default, " +		"1=disable, 2=enable (default: 0)");  /*   * set bt_coex_active to true, uCode will do kill/defer diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5d8d2f44592..2f446a35351 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -101,6 +101,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,  			     struct ieee80211_vif *vif,  			     struct ieee80211_bss_conf *bss_conf,  			     u32 changes); +void iwlagn_config_ht40(struct ieee80211_conf *conf, +			struct iwl_rxon_context *ctx);  /* uCode */  int iwlagn_rx_calib_result(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f9e9170e977..b24623b3bdb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1505,11 +1505,23 @@ void iwl_setup_watchdog(struct iwl_priv *priv)  {  	unsigned int timeout = priv->cfg->base_params->wd_timeout; -	if (timeout && !iwlagn_mod_params.wd_disable) -		mod_timer(&priv->watchdog, -			  jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); -	else -		del_timer(&priv->watchdog); +	if (!iwlagn_mod_params.wd_disable) { +		/* use system default */ +		if (timeout && !priv->cfg->base_params->wd_disable) +			mod_timer(&priv->watchdog, +				jiffies + +				msecs_to_jiffies(IWL_WD_TICK(timeout))); +		else +			del_timer(&priv->watchdog); +	} else { +		/* module parameter overwrite default configuration */ +		if (timeout && iwlagn_mod_params.wd_disable == 2) +			mod_timer(&priv->watchdog, +				jiffies + +				msecs_to_jiffies(IWL_WD_TICK(timeout))); +		else +			del_timer(&priv->watchdog); +	}  }  /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f1d9d0c13e4..6da53a36c1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -113,6 +113,7 @@ struct iwl_lib_ops {   * @shadow_reg_enable: HW shadhow register bit   * @no_idle_support: do not support idle mode   * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up + * wd_disable: disable watchdog timer   */  struct iwl_base_params {  	int eeprom_size; @@ -134,6 +135,7 @@ struct iwl_base_params {  	const bool shadow_reg_enable;  	const bool no_idle_support;  	const bool hd_v2; +	const bool wd_disable;  };  /*   * @advanced_bt_coexist: support advanced bt coexist diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 47be77a8a0a..30af95b19f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -120,7 +120,7 @@ extern struct iwl_mod_params iwlagn_mod_params;   * @restart_fw: restart firmware, default = 1   * @plcp_check: enable plcp health check, default = true   * @ack_check: disable ack health check, default = false - * @wd_disable: enable stuck queue check, default = false + * @wd_disable: enable stuck queue check, default = 0   * @bt_coex_active: enable bt coex, default = true   * @led_mode: system default, default = 0   * @no_sleep_autoadjust: disable autoadjust, default = true @@ -141,7 +141,7 @@ struct iwl_mod_params {  	int restart_fw;  	bool plcp_check;  	bool ack_check; -	bool wd_disable; +	int  wd_disable;  	bool bt_coex_active;  	int led_mode;  	bool no_sleep_autoadjust; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 2ac75427f10..304b2ea0375 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -990,29 +990,16 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans)  	return 0;  } -static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans) +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)  {  	unsigned long flags; -	struct iwl_trans_pcie *trans_pcie = -		IWL_TRANS_GET_PCIE_TRANS(trans); +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +	/* tell the device to stop sending interrupts */  	spin_lock_irqsave(&trans->shrd->lock, flags);  	iwl_disable_interrupts(trans);  	spin_unlock_irqrestore(&trans->shrd->lock, flags); -	/* wait to make sure we flush pending tasklet*/ -	synchronize_irq(bus(trans)->irq); -	tasklet_kill(&trans_pcie->irq_tasklet); -} - -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) -{ -	/* stop and reset the on-board processor */ -	iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - -	/* tell the device to stop sending interrupts */ -	iwl_trans_pcie_disable_sync_irq(trans); -  	/* device going down, Stop using ICT table */  	iwl_disable_ict(trans); @@ -1039,6 +1026,20 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)  	/* Stop the device, and put it in low power state */  	iwl_apm_stop(priv(trans)); + +	/* Upon stop, the APM issues an interrupt if HW RF kill is set. +	 * Clean again the interrupt here +	 */ +	spin_lock_irqsave(&trans->shrd->lock, flags); +	iwl_disable_interrupts(trans); +	spin_unlock_irqrestore(&trans->shrd->lock, flags); + +	/* wait to make sure we flush pending tasklet*/ +	synchronize_irq(bus(trans)->irq); +	tasklet_kill(&trans_pcie->irq_tasklet); + +	/* stop and reset the on-board processor */ +	iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);  }  static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 89f34ad8d34..d1d84e0e30f 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -635,7 +635,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,  			if (channel &&  			    !(channel->flags & IEEE80211_CHAN_DISABLED)) {  				bss = cfg80211_inform_bss(wiphy, channel, -					bssid, le64_to_cpu(*(__le64 *)tsfdesc), +					bssid, get_unaligned_le64(tsfdesc),  					capa, intvl, ie, ielen,  					LBS_SCAN_RSSI_TO_MBM(rssi),  					GFP_KERNEL); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 0c87f42fa66..50b1ee7721e 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -995,6 +995,7 @@ static int if_spi_host_to_card(struct lbs_private *priv,  		spin_unlock_irqrestore(&card->buffer_lock, flags);  		break;  	default: +		kfree(packet);  		netdev_err(priv->dev, "can't transfer buffer of type %d\n",  			   type);  		err = -EINVAL; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 8a18bcc23b2..b8b9d37b01a 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -819,8 +819,10 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,  			wildcard_ssid_tlv->header.len = cpu_to_le16(  				(u16) (ssid_len + sizeof(wildcard_ssid_tlv->  							 max_ssid_length))); -			wildcard_ssid_tlv->max_ssid_length = -				user_scan_in->ssid_list[ssid_idx].max_len; + +			/* max_ssid_length = 0 tells firmware to perform +			   specific scan for the SSID filled */ +			wildcard_ssid_tlv->max_ssid_length = 0;  			memcpy(wildcard_ssid_tlv->ssid,  			       user_scan_in->ssid_list[ssid_idx].ssid, diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 546551389a1..7faed62c637 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -584,8 +584,6 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)  	mutex_lock(&priv->mutex);  	WARN_ON(priv->fw_state != FW_STATE_READY); -	cancel_work_sync(&priv->work); -  	p54spi_power_off(priv);  	spin_lock_irqsave(&priv->tx_lock, flags);  	INIT_LIST_HEAD(&priv->tx_pending); @@ -593,6 +591,8 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)  	priv->fw_state = FW_STATE_OFF;  	mutex_unlock(&priv->mutex); + +	cancel_work_sync(&priv->work);  }  static int __devinit p54spi_probe(struct spi_device *spi) @@ -652,6 +652,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)  	init_completion(&priv->fw_comp);  	INIT_LIST_HEAD(&priv->tx_pending);  	mutex_init(&priv->mutex); +	spin_lock_init(&priv->tx_lock);  	SET_IEEE80211_DEV(hw, &spi->dev);  	priv->common.open = p54spi_op_start;  	priv->common.stop = p54spi_op_stop; diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index f83bc5a5e81..4e44b1af119 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -778,7 +778,7 @@ prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,  		dwrq->flags = 0;  		dwrq->length = 0;  	} -	essid->octets[essid->length] = '\0'; +	essid->octets[dwrq->length] = '\0';  	memcpy(extra, essid->octets, dwrq->length);  	kfree(essid); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 25dab298713..e5df380d4fb 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3773,7 +3773,7 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)  	/* Apparently the data is read from end to start */  	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®);  	/* The returned value is in CPU order, but eeprom is le */ -	rt2x00dev->eeprom[i] = cpu_to_le32(reg); +	*(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);  	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®);  	*(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);  	rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f1565792f27..377876315b8 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -919,6 +919,7 @@ static struct usb_device_id rt2800usb_device_table[] = {  	{ USB_DEVICE(0x050d, 0x935b) },  	/* Buffalo */  	{ USB_DEVICE(0x0411, 0x00e8) }, +	{ USB_DEVICE(0x0411, 0x0158) },  	{ USB_DEVICE(0x0411, 0x016f) },  	{ USB_DEVICE(0x0411, 0x01a2) },  	/* Corega */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 2ec5c00235e..99ff12d0c29 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -943,6 +943,7 @@ struct rt2x00_dev {  	 * Powersaving work  	 */  	struct delayed_work autowakeup_work; +	struct work_struct sleep_work;  	/*  	 * Data queue arrays for RX, TX, Beacon and ATIM. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e1fb2a8569b..edd317fa7c0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -465,6 +465,23 @@ static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie)  	return NULL;  } +static void rt2x00lib_sleep(struct work_struct *work) +{ +	struct rt2x00_dev *rt2x00dev = +	    container_of(work, struct rt2x00_dev, sleep_work); + +	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) +		return; + +	/* +	 * Check again is powersaving is enabled, to prevent races from delayed +	 * work execution. +	 */ +	if (!test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) +		rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, +				 IEEE80211_CONF_CHANGE_PS); +} +  static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,  				      struct sk_buff *skb,  				      struct rxdone_entry_desc *rxdesc) @@ -512,8 +529,7 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,  	cam |= (tim_ie->bitmap_ctrl & 0x01);  	if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) -		rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, -				 IEEE80211_CONF_CHANGE_PS); +		queue_work(rt2x00dev->workqueue, &rt2x00dev->sleep_work);  }  static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, @@ -1141,6 +1157,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)  	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);  	INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); +	INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);  	/*  	 * Let the driver probe the device to detect the capabilities. @@ -1197,6 +1214,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)  	 */  	cancel_work_sync(&rt2x00dev->intf_work);  	cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); +	cancel_work_sync(&rt2x00dev->sleep_work);  	if (rt2x00_is_usb(rt2x00dev)) {  		del_timer_sync(&rt2x00dev->txstatus_timer);  		cancel_work_sync(&rt2x00dev->rxdone_work); diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index db526284454..55c8e50f45f 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -395,7 +395,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw)  	if (mac->link_state != MAC80211_LINKED)  		return; -	spin_lock(&rtlpriv->locks.lps_lock); +	spin_lock_irq(&rtlpriv->locks.lps_lock);  	/* Idle for a while if we connect to AP a while ago. */  	if (mac->cnt_after_linked >= 2) { @@ -407,7 +407,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw)  		}  	} -	spin_unlock(&rtlpriv->locks.lps_lock); +	spin_unlock_irq(&rtlpriv->locks.lps_lock);  }  /*Leave the leisure power save mode.*/ @@ -416,8 +416,9 @@ void rtl_lps_leave(struct ieee80211_hw *hw)  	struct rtl_priv *rtlpriv = rtl_priv(hw);  	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));  	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	unsigned long flags; -	spin_lock(&rtlpriv->locks.lps_lock); +	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flags);  	if (ppsc->fwctrl_lps) {  		if (ppsc->dot11_psmode != EACTIVE) { @@ -438,7 +439,7 @@ void rtl_lps_leave(struct ieee80211_hw *hw)  			rtl_lps_set_psmode(hw, EACTIVE);  		}  	} -	spin_unlock(&rtlpriv->locks.lps_lock); +	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flags);  }  /* For sw LPS*/ @@ -539,9 +540,9 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw)  		RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);  	} -	spin_lock(&rtlpriv->locks.lps_lock); +	spin_lock_irq(&rtlpriv->locks.lps_lock);  	rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); -	spin_unlock(&rtlpriv->locks.lps_lock); +	spin_unlock_irq(&rtlpriv->locks.lps_lock);  }  void rtl_swlps_rfon_wq_callback(void *data) @@ -574,9 +575,9 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)  	if (rtlpriv->link_info.busytraffic)  		return; -	spin_lock(&rtlpriv->locks.lps_lock); +	spin_lock_irq(&rtlpriv->locks.lps_lock);  	rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); -	spin_unlock(&rtlpriv->locks.lps_lock); +	spin_unlock_irq(&rtlpriv->locks.lps_lock);  	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&  		!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 266cc871c72..2c2e9519a2e 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -162,6 +162,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,  		return -ENOENT;  	} +	/* if we're already stopping ignore any new requests to stop */ +	if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { +		spin_unlock_bh(&sta->lock); +		return -EALREADY; +	} +  	if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {  		/* not even started yet! */  		ieee80211_assign_tid_tx(sta, tid, NULL); @@ -170,6 +176,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,  		return 0;  	} +	set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); +  	spin_unlock_bh(&sta->lock);  #ifdef CONFIG_MAC80211_HT_DEBUG @@ -177,8 +185,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,  	       sta->sta.addr, tid);  #endif /* CONFIG_MAC80211_HT_DEBUG */ -	set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); -  	del_timer_sync(&tid_tx->addba_resp_timer);  	del_timer_sync(&tid_tx->session_timer); @@ -189,6 +195,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,  	 */  	clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); +	/* +	 * There might be a few packets being processed right now (on +	 * another CPU) that have already gotten past the aggregation +	 * check when it was still OPERATIONAL and consequently have +	 * IEEE80211_TX_CTL_AMPDU set. In that case, this code might +	 * call into the driver at the same time or even before the +	 * TX paths calls into it, which could confuse the driver. +	 * +	 * Wait for all currently running TX paths to finish before +	 * telling the driver. New packets will not go through since +	 * the aggregation session is no longer OPERATIONAL. +	 */ +	synchronize_net(); +  	tid_tx->stop_initiator = initiator;  	tid_tx->tx_stop = tx; @@ -781,11 +801,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,  		goto out;  	} -	del_timer(&tid_tx->addba_resp_timer); +	del_timer_sync(&tid_tx->addba_resp_timer);  #ifdef CONFIG_MAC80211_HT_DEBUG  	printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);  #endif + +	/* +	 * addba_resp_timer may have fired before we got here, and +	 * caused WANT_STOP to be set. If the stop then was already +	 * processed further, STOPPING might be set. +	 */ +	if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || +	    test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { +#ifdef CONFIG_MAC80211_HT_DEBUG +		printk(KERN_DEBUG +		       "got addBA resp for tid %d but we already gave up\n", +		       tid); +#endif +		goto out; +	} +  	/*  	 * IEEE 802.11-2007 7.3.1.14:  	 * In an ADDBA Response frame, when the Status Code field diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index edfdd74d435..2406b3e7393 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -274,9 +274,9 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,  		PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack"); -		PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: " -			     "3839 bytes");  		PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: " +			     "3839 bytes"); +		PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: "  			     "7935 bytes");  		/* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 944bed35d92..24cc50b963a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -738,6 +738,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	if (!local->int_scan_req)  		return -ENOMEM; +	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { +		if (!local->hw.wiphy->bands[band]) +			continue; +		local->int_scan_req->rates[band] = (u32) -1; +	} +  	/* if low-level driver supports AP, we also support VLAN */  	if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {  		hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a6ad19757ba..09019d13594 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2301,6 +2301,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)  	cancel_work_sync(&ifmgd->request_smps_work); +	cancel_work_sync(&ifmgd->monitor_work);  	cancel_work_sync(&ifmgd->beacon_connection_loss_work);  	if (del_timer_sync(&ifmgd->timer))  		set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); @@ -2309,7 +2310,6 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)  	if (del_timer_sync(&ifmgd->chswitch_timer))  		set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); -	cancel_work_sync(&ifmgd->monitor_work);  	/* these will just be re-established on connection */  	del_timer_sync(&ifmgd->conn_mon_timer);  	del_timer_sync(&ifmgd->bcn_mon_timer); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1e231e95f46..daf5cde65b3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -141,8 +141,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,  	pos++;  	/* IEEE80211_RADIOTAP_RATE */ -	if (status->flag & RX_FLAG_HT) { +	if (!rate || status->flag & RX_FLAG_HT) {  		/* +		 * Without rate information don't add it. If we have,  		 * MCS information is a separate field in radiotap,  		 * added below. The byte here is needed as padding  		 * for the channel though, so initialise it to 0. @@ -163,12 +164,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,  	else if (status->flag & RX_FLAG_HT)  		put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,  				   pos); -	else if (rate->flags & IEEE80211_RATE_ERP_G) +	else if (rate && rate->flags & IEEE80211_RATE_ERP_G)  		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,  				   pos); -	else +	else if (rate)  		put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,  				   pos); +	else +		put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos);  	pos += 2;  	/* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index a9da6ee6980..46222ce0e5b 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -260,7 +260,7 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;  	struct ieee80211_radiotap_header *rthdr;  	unsigned char *pos; -	__le16 txflags; +	u16 txflags;  	rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len); @@ -290,13 +290,13 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band  	txflags = 0;  	if (!(info->flags & IEEE80211_TX_STAT_ACK) &&  	    !is_multicast_ether_addr(hdr->addr1)) -		txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); +		txflags |= IEEE80211_RADIOTAP_F_TX_FAIL;  	if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||  	    (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) -		txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); +		txflags |= IEEE80211_RADIOTAP_F_TX_CTS;  	else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) -		txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); +		txflags |= IEEE80211_RADIOTAP_F_TX_RTS;  	put_unaligned_le16(txflags, pos);  	pos += 2; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5f7c1c601dc..5243c2cadee 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1034,6 +1034,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,  	skb = ieee80211_probereq_get(&local->hw, &sdata->vif,  				     ssid, ssid_len,  				     buf, buf_len); +	if (!skb) +		goto out;  	if (dst) {  		mgmt = (struct ieee80211_mgmt *) skb->data; @@ -1042,6 +1044,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,  	}  	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + + out:  	kfree(buf);  	return skb; @@ -1188,7 +1192,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)  					     struct ieee80211_sub_if_data,  					     u.ap); -			memset(&sta->sta.drv_priv, 0, hw->sta_data_size);  			WARN_ON(drv_sta_add(local, sdata, &sta->sta));  		}  	} diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0ee512b85a1..8a9b4d817ae 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -89,8 +89,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {  	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },  	[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, -	[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, -	[NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, +	[NL80211_ATTR_MAC] = { .len = ETH_ALEN }, +	[NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },  	[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },  	[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0e67016ce78..70b171a52ae 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -57,8 +57,17 @@  #define REG_DBG_PRINT(args...)  #endif +static struct regulatory_request core_request_world = { +	.initiator = NL80211_REGDOM_SET_BY_CORE, +	.alpha2[0] = '0', +	.alpha2[1] = '0', +	.intersect = false, +	.processed = true, +	.country_ie_env = ENVIRON_ANY, +}; +  /* Receipt of information from last regulatory request */ -static struct regulatory_request *last_request; +static struct regulatory_request *last_request = &core_request_world;  /* To trigger userspace events */  static struct platform_device *reg_pdev; @@ -150,7 +159,7 @@ static char user_alpha2[2];  module_param(ieee80211_regdom, charp, 0444);  MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); -static void reset_regdomains(void) +static void reset_regdomains(bool full_reset)  {  	/* avoid freeing static information or freeing something twice */  	if (cfg80211_regdomain == cfg80211_world_regdom) @@ -165,6 +174,13 @@ static void reset_regdomains(void)  	cfg80211_world_regdom = &world_regdom;  	cfg80211_regdomain = NULL; + +	if (!full_reset) +		return; + +	if (last_request != &core_request_world) +		kfree(last_request); +	last_request = &core_request_world;  }  /* @@ -175,7 +191,7 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd)  {  	BUG_ON(!last_request); -	reset_regdomains(); +	reset_regdomains(false);  	cfg80211_world_regdom = rd;  	cfg80211_regdomain = rd; @@ -1409,7 +1425,8 @@ static int __regulatory_hint(struct wiphy *wiphy,  	}  new_request: -	kfree(last_request); +	if (last_request != &core_request_world) +		kfree(last_request);  	last_request = pending_request;  	last_request->intersect = intersect; @@ -1579,9 +1596,6 @@ static int regulatory_hint_core(const char *alpha2)  {  	struct regulatory_request *request; -	kfree(last_request); -	last_request = NULL; -  	request = kzalloc(sizeof(struct regulatory_request),  			  GFP_KERNEL);  	if (!request) @@ -1779,7 +1793,7 @@ static void restore_regulatory_settings(bool reset_user)  	mutex_lock(&cfg80211_mutex);  	mutex_lock(®_mutex); -	reset_regdomains(); +	reset_regdomains(true);  	restore_alpha2(alpha2, reset_user);  	/* @@ -2076,12 +2090,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)  	}  	request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); +	if (!request_wiphy && +	    (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || +	     last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { +		schedule_delayed_work(®_timeout, 0); +		return -ENODEV; +	}  	if (!last_request->intersect) {  		int r;  		if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { -			reset_regdomains(); +			reset_regdomains(false);  			cfg80211_regdomain = rd;  			return 0;  		} @@ -2102,7 +2122,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)  		if (r)  			return r; -		reset_regdomains(); +		reset_regdomains(false);  		cfg80211_regdomain = rd;  		return 0;  	} @@ -2127,7 +2147,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)  		rd = NULL; -		reset_regdomains(); +		reset_regdomains(false);  		cfg80211_regdomain = intersected_rd;  		return 0; @@ -2147,7 +2167,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)  	kfree(rd);  	rd = NULL; -	reset_regdomains(); +	reset_regdomains(false);  	cfg80211_regdomain = intersected_rd;  	return 0; @@ -2300,9 +2320,9 @@ void /* __init_or_exit */ regulatory_exit(void)  	mutex_lock(&cfg80211_mutex);  	mutex_lock(®_mutex); -	reset_regdomains(); +	reset_regdomains(true); -	kfree(last_request); +	dev_set_uevent_suppress(®_pdev->dev, true);  	platform_device_unregister(reg_pdev);  |