diff options
Diffstat (limited to 'net/mac80211/main.c')
| -rw-r--r-- | net/mac80211/main.c | 215 | 
1 files changed, 147 insertions, 68 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 21d5d44444d..d17c26d6e36 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -148,6 +148,8 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {  		if (!rcu_access_pointer(sdata->vif.chanctx_conf))  			continue; +		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) +			continue;  		power = min(power, sdata->vif.bss_conf.txpower);  	}  	rcu_read_unlock(); @@ -199,7 +201,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,  {  	struct ieee80211_local *local = sdata->local; -	if (!changed) +	if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN)  		return;  	drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); @@ -250,12 +252,8 @@ static void ieee80211_restart_work(struct work_struct *work)  	/* wait for scan work complete */  	flush_workqueue(local->workqueue); -	mutex_lock(&local->mtx); -	WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || -	     rcu_dereference_protected(local->sched_scan_sdata, -				       lockdep_is_held(&local->mtx)), -		"%s called with hardware scan in progress\n", __func__); -	mutex_unlock(&local->mtx); +	WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), +	     "%s called with hardware scan in progress\n", __func__);  	rtnl_lock();  	ieee80211_scan_cancel(local); @@ -342,7 +340,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,  	sdata_unlock(sdata); -	return NOTIFY_DONE; +	return NOTIFY_OK;  }  #endif @@ -373,7 +371,7 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb,  	drv_ipv6_addr_change(local, sdata, idev); -	return NOTIFY_DONE; +	return NOTIFY_OK;  }  #endif @@ -448,7 +446,9 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {  	.cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 |  				IEEE80211_HT_CAP_MAX_AMSDU |  				IEEE80211_HT_CAP_SGI_20 | -				IEEE80211_HT_CAP_SGI_40), +				IEEE80211_HT_CAP_SGI_40 | +				IEEE80211_HT_CAP_LDPC_CODING | +				IEEE80211_HT_CAP_40MHZ_INTOLERANT),  	.mcs = {  		.rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,  			     0xff, 0xff, 0xff, 0xff, 0xff, }, @@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  }  EXPORT_SYMBOL(ieee80211_alloc_hw); -int ieee80211_register_hw(struct ieee80211_hw *hw) +static int ieee80211_init_cipher_suites(struct ieee80211_local *local)  { -	struct ieee80211_local *local = hw_to_local(hw); -	int result, i; -	enum ieee80211_band band; -	int channels, max_bitrates; -	bool supp_ht, supp_vht; -	netdev_features_t feature_whitelist; -	struct cfg80211_chan_def dflt_chandef = {}; +	bool have_wep = !(IS_ERR(local->wep_tx_tfm) || +			  IS_ERR(local->wep_rx_tfm)); +	bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; +	const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes; +	int n_suites = 0, r = 0, w = 0; +	u32 *suites;  	static const u32 cipher_suites[] = {  		/* keep WEP first, it may be removed below */  		WLAN_CIPHER_SUITE_WEP40, @@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  		WLAN_CIPHER_SUITE_AES_CMAC  	}; +	/* Driver specifies the ciphers, we have nothing to do... */ +	if (local->hw.wiphy->cipher_suites && have_wep) +		return 0; + +	/* Set up cipher suites if driver relies on mac80211 cipher defs */ +	if (!local->hw.wiphy->cipher_suites && !cs) { +		local->hw.wiphy->cipher_suites = cipher_suites; +		local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + +		if (!have_mfp) +			local->hw.wiphy->n_cipher_suites--; + +		if (!have_wep) { +			local->hw.wiphy->cipher_suites += 2; +			local->hw.wiphy->n_cipher_suites -= 2; +		} + +		return 0; +	} + +	if (!local->hw.wiphy->cipher_suites) { +		/* +		 * Driver specifies cipher schemes only +		 * We start counting ciphers defined by schemes, TKIP and CCMP +		 */ +		n_suites = local->hw.n_cipher_schemes + 2; + +		/* check if we have WEP40 and WEP104 */ +		if (have_wep) +			n_suites += 2; + +		/* check if we have AES_CMAC */ +		if (have_mfp) +			n_suites++; + +		suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); +		if (!suites) +			return -ENOMEM; + +		suites[w++] = WLAN_CIPHER_SUITE_CCMP; +		suites[w++] = WLAN_CIPHER_SUITE_TKIP; + +		if (have_wep) { +			suites[w++] = WLAN_CIPHER_SUITE_WEP40; +			suites[w++] = WLAN_CIPHER_SUITE_WEP104; +		} + +		if (have_mfp) +			suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; + +		for (r = 0; r < local->hw.n_cipher_schemes; r++) +			suites[w++] = cs[r].cipher; +	} else { +		/* Driver provides cipher suites, but we need to exclude WEP */ +		suites = kmemdup(local->hw.wiphy->cipher_suites, +				 sizeof(u32) * local->hw.wiphy->n_cipher_suites, +				 GFP_KERNEL); +		if (!suites) +			return -ENOMEM; + +		for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { +			u32 suite = local->hw.wiphy->cipher_suites[r]; + +			if (suite == WLAN_CIPHER_SUITE_WEP40 || +			    suite == WLAN_CIPHER_SUITE_WEP104) +				continue; +			suites[w++] = suite; +		} +	} + +	local->hw.wiphy->cipher_suites = suites; +	local->hw.wiphy->n_cipher_suites = w; +	local->wiphy_ciphers_allocated = true; + +	return 0; +} + +int ieee80211_register_hw(struct ieee80211_hw *hw) +{ +	struct ieee80211_local *local = hw_to_local(hw); +	int result, i; +	enum ieee80211_band band; +	int channels, max_bitrates; +	bool supp_ht, supp_vht; +	netdev_features_t feature_whitelist; +	struct cfg80211_chan_def dflt_chandef = {}; +  	if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&  	    (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||  	     local->hw.offchannel_tx_hw_queue >= local->hw.queues)) @@ -764,17 +850,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  		/* TODO: consider VHT for RX chains, hopefully it's the same */  	} -	local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + -				      sizeof(void *) * channels, GFP_KERNEL); -	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); @@ -798,6 +873,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  				return -EINVAL;  	} +	local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + +				      sizeof(void *) * channels, GFP_KERNEL); +	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; +	} +  #ifndef CONFIG_MAC80211_MESH  	/* mesh depends on Kconfig, but drivers should set it if they want */  	local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); @@ -811,10 +897,15 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	/* mac80211 supports control port protocol changing */  	local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; -	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) +	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {  		local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; -	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) +	} else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {  		local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; +		if (hw->max_signal <= 0) { +			result = -EINVAL; +			goto fail_wiphy_register; +		} +	}  	WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)  	     && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), @@ -851,43 +942,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	if (local->hw.wiphy->max_scan_ie_len)  		local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; -	/* Set up cipher suites unless driver already did */ -	if (!local->hw.wiphy->cipher_suites) { -		local->hw.wiphy->cipher_suites = cipher_suites; -		local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); -		if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) -			local->hw.wiphy->n_cipher_suites--; -	} -	if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { -		if (local->hw.wiphy->cipher_suites == cipher_suites) { -			local->hw.wiphy->cipher_suites += 2; -			local->hw.wiphy->n_cipher_suites -= 2; -		} else { -			u32 *suites; -			int r, w = 0; - -			/* Filter out WEP */ - -			suites = kmemdup( -				local->hw.wiphy->cipher_suites, -				sizeof(u32) * local->hw.wiphy->n_cipher_suites, -				GFP_KERNEL); -			if (!suites) { -				result = -ENOMEM; -				goto fail_wiphy_register; -			} -			for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { -				u32 suite = local->hw.wiphy->cipher_suites[r]; -				if (suite == WLAN_CIPHER_SUITE_WEP40 || -				    suite == WLAN_CIPHER_SUITE_WEP104) -					continue; -				suites[w++] = suite; -			} -			local->hw.wiphy->cipher_suites = suites; -			local->hw.wiphy->n_cipher_suites = w; -			local->wiphy_ciphers_allocated = true; -		} -	} +	WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, +					 local->hw.n_cipher_schemes)); + +	result = ieee80211_init_cipher_suites(local); +	if (result < 0) +		goto fail_wiphy_register;  	if (!local->ops->remain_on_channel)  		local->hw.wiphy->max_remain_on_channel_duration = 5000; @@ -896,6 +956,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  	if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)  		local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; +	local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; +  	result = wiphy_register(local->hw.wiphy);  	if (result < 0)  		goto fail_wiphy_register; @@ -940,6 +1002,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  		wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",  			    result); +	local->hw.conf.flags = IEEE80211_CONF_IDLE; +  	ieee80211_led_init(local);  	rtnl_lock(); @@ -1018,6 +1082,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)  }  EXPORT_SYMBOL(ieee80211_register_hw); +void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, +			struct net_device *napi_dev, +			int (*poll)(struct napi_struct *, int), +			int weight) +{ +	struct ieee80211_local *local = hw_to_local(hw); + +	netif_napi_add(napi_dev, napi, poll, weight); +	local->napi = napi; +} +EXPORT_SYMBOL_GPL(ieee80211_napi_add); +  void ieee80211_unregister_hw(struct ieee80211_hw *hw)  {  	struct ieee80211_local *local = hw_to_local(hw); @@ -1047,6 +1123,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)  	cancel_work_sync(&local->restart_work);  	cancel_work_sync(&local->reconfig_filter); +	flush_work(&local->sched_scan_stopped_work);  	ieee80211_clear_tx_pending(local);  	rate_control_deinitialize(local); @@ -1087,6 +1164,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)  		     ieee80211_free_ack_frame, NULL);  	idr_destroy(&local->ack_status_frames); +	kfree(rcu_access_pointer(local->tx_latency)); +  	wiphy_free(local->hw.wiphy);  }  EXPORT_SYMBOL(ieee80211_free_hw);  | 
