diff options
Diffstat (limited to 'net/wireless/util.c')
| -rw-r--r-- | net/wireless/util.c | 209 | 
1 files changed, 146 insertions, 63 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index e5872ff2c27c..728f1c0dc70d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -476,7 +476,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,  EXPORT_SYMBOL(ieee80211_data_to_8023);  int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, -			     enum nl80211_iftype iftype, u8 *bssid, bool qos) +			     enum nl80211_iftype iftype, +			     const u8 *bssid, bool qos)  {  	struct ieee80211_hdr hdr;  	u16 hdrlen, ethertype; @@ -770,7 +771,7 @@ EXPORT_SYMBOL(ieee80211_bss_get_ie);  void cfg80211_upload_connect_keys(struct wireless_dev *wdev)  { -	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); +	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);  	struct net_device *dev = wdev->netdev;  	int i; @@ -839,6 +840,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)  			__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,  					       ev->ij.channel);  			break; +		case EVENT_STOPPED: +			__cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev); +			break;  		}  		wdev_unlock(wdev); @@ -888,11 +892,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,  		return -EBUSY;  	if (ntype != otype && netif_running(dev)) { -		err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, -						    ntype); -		if (err) -			return err; -  		dev->ieee80211_ptr->use_4addr = false;  		dev->ieee80211_ptr->mesh_id_up_len = 0;  		wdev_lock(dev->ieee80211_ptr); @@ -1268,6 +1267,120 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,  	return res;  } +int cfg80211_iter_combinations(struct wiphy *wiphy, +			       const int num_different_channels, +			       const u8 radar_detect, +			       const int iftype_num[NUM_NL80211_IFTYPES], +			       void (*iter)(const struct ieee80211_iface_combination *c, +					    void *data), +			       void *data) +{ +	const struct ieee80211_regdomain *regdom; +	enum nl80211_dfs_regions region = 0; +	int i, j, iftype; +	int num_interfaces = 0; +	u32 used_iftypes = 0; + +	if (radar_detect) { +		rcu_read_lock(); +		regdom = rcu_dereference(cfg80211_regdomain); +		if (regdom) +			region = regdom->dfs_region; +		rcu_read_unlock(); +	} + +	for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { +		num_interfaces += iftype_num[iftype]; +		if (iftype_num[iftype] > 0 && +		    !(wiphy->software_iftypes & BIT(iftype))) +			used_iftypes |= BIT(iftype); +	} + +	for (i = 0; i < wiphy->n_iface_combinations; i++) { +		const struct ieee80211_iface_combination *c; +		struct ieee80211_iface_limit *limits; +		u32 all_iftypes = 0; + +		c = &wiphy->iface_combinations[i]; + +		if (num_interfaces > c->max_interfaces) +			continue; +		if (num_different_channels > c->num_different_channels) +			continue; + +		limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, +				 GFP_KERNEL); +		if (!limits) +			return -ENOMEM; + +		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { +			if (wiphy->software_iftypes & BIT(iftype)) +				continue; +			for (j = 0; j < c->n_limits; j++) { +				all_iftypes |= limits[j].types; +				if (!(limits[j].types & BIT(iftype))) +					continue; +				if (limits[j].max < iftype_num[iftype]) +					goto cont; +				limits[j].max -= iftype_num[iftype]; +			} +		} + +		if (radar_detect != (c->radar_detect_widths & radar_detect)) +			goto cont; + +		if (radar_detect && c->radar_detect_regions && +		    !(c->radar_detect_regions & BIT(region))) +			goto cont; + +		/* Finally check that all iftypes that we're currently +		 * using are actually part of this combination. If they +		 * aren't then we can't use this combination and have +		 * to continue to the next. +		 */ +		if ((all_iftypes & used_iftypes) != used_iftypes) +			goto cont; + +		/* This combination covered all interface types and +		 * supported the requested numbers, so we're good. +		 */ + +		(*iter)(c, data); + cont: +		kfree(limits); +	} + +	return 0; +} +EXPORT_SYMBOL(cfg80211_iter_combinations); + +static void +cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c, +			  void *data) +{ +	int *num = data; +	(*num)++; +} + +int cfg80211_check_combinations(struct wiphy *wiphy, +				const int num_different_channels, +				const u8 radar_detect, +				const int iftype_num[NUM_NL80211_IFTYPES]) +{ +	int err, num = 0; + +	err = cfg80211_iter_combinations(wiphy, num_different_channels, +					 radar_detect, iftype_num, +					 cfg80211_iter_sum_ifcombs, &num); +	if (err) +		return err; +	if (num == 0) +		return -EBUSY; + +	return 0; +} +EXPORT_SYMBOL(cfg80211_check_combinations); +  int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,  				 struct wireless_dev *wdev,  				 enum nl80211_iftype iftype, @@ -1276,7 +1389,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,  				 u8 radar_detect)  {  	struct wireless_dev *wdev_iter; -	u32 used_iftypes = BIT(iftype);  	int num[NUM_NL80211_IFTYPES];  	struct ieee80211_channel  			*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; @@ -1284,7 +1396,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,  	enum cfg80211_chan_mode chmode;  	int num_different_channels = 0;  	int total = 1; -	int i, j; +	int i;  	ASSERT_RTNL(); @@ -1306,6 +1418,11 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,  	num[iftype] = 1; +	/* TODO: We'll probably not need this anymore, since this +	 * should only be called with CHAN_MODE_UNDEFINED. There are +	 * still a couple of pending calls where other chanmodes are +	 * used, but we should get rid of them. +	 */  	switch (chanmode) {  	case CHAN_MODE_UNDEFINED:  		break; @@ -1369,65 +1486,13 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,  		num[wdev_iter->iftype]++;  		total++; -		used_iftypes |= BIT(wdev_iter->iftype);  	}  	if (total == 1 && !radar_detect)  		return 0; -	for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { -		const struct ieee80211_iface_combination *c; -		struct ieee80211_iface_limit *limits; -		u32 all_iftypes = 0; - -		c = &rdev->wiphy.iface_combinations[i]; - -		if (total > c->max_interfaces) -			continue; -		if (num_different_channels > c->num_different_channels) -			continue; - -		limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, -				 GFP_KERNEL); -		if (!limits) -			return -ENOMEM; - -		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { -			if (rdev->wiphy.software_iftypes & BIT(iftype)) -				continue; -			for (j = 0; j < c->n_limits; j++) { -				all_iftypes |= limits[j].types; -				if (!(limits[j].types & BIT(iftype))) -					continue; -				if (limits[j].max < num[iftype]) -					goto cont; -				limits[j].max -= num[iftype]; -			} -		} - -		if (radar_detect && !(c->radar_detect_widths & radar_detect)) -			goto cont; - -		/* -		 * Finally check that all iftypes that we're currently -		 * using are actually part of this combination. If they -		 * aren't then we can't use this combination and have -		 * to continue to the next. -		 */ -		if ((all_iftypes & used_iftypes) != used_iftypes) -			goto cont; - -		/* -		 * This combination covered all interface types and -		 * supported the requested numbers, so we're good. -		 */ -		kfree(limits); -		return 0; - cont: -		kfree(limits); -	} - -	return -EBUSY; +	return cfg80211_check_combinations(&rdev->wiphy, num_different_channels, +					   radar_detect, num);  }  int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, @@ -1481,6 +1546,24 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)  }  EXPORT_SYMBOL(ieee80211_get_num_supported_channels); +int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr, +			 struct station_info *sinfo) +{ +	struct cfg80211_registered_device *rdev; +	struct wireless_dev *wdev; + +	wdev = dev->ieee80211_ptr; +	if (!wdev) +		return -EOPNOTSUPP; + +	rdev = wiphy_to_rdev(wdev->wiphy); +	if (!rdev->ops->get_station) +		return -EOPNOTSUPP; + +	return rdev_get_station(rdev, dev, mac_addr, sinfo); +} +EXPORT_SYMBOL(cfg80211_get_station); +  /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */  /* Ethernet-II snap header (RFC1042 for most EtherTypes) */  const unsigned char rfc1042_header[] __aligned(2) =  |