Beispiel #1
0
int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
			 struct net_device *dev,
			 struct mesh_setup *setup,
			 const struct mesh_config *conf)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

	BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);

	ASSERT_WDEV_LOCK(wdev);

	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;

	if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
	      setup->is_secure)
		return -EOPNOTSUPP;

	if (wdev->mesh_id_len)
		return -EALREADY;

	if (!setup->mesh_id_len)
		return -EINVAL;

	if (!rdev->ops->join_mesh)
		return -EOPNOTSUPP;

	if (!setup->chandef.chan) {
		/* if no channel explicitly given, use preset channel */
		setup->chandef = wdev->preset_chandef;
	}

	if (!setup->chandef.chan) {
		/* if we don't have that either, use the first usable channel */
		enum nl80211_band band;

		for (band = 0; band < NUM_NL80211_BANDS; band++) {
			struct ieee80211_supported_band *sband;
			struct ieee80211_channel *chan;
			int i;

			sband = rdev->wiphy.bands[band];
			if (!sband)
				continue;

			for (i = 0; i < sband->n_channels; i++) {
				chan = &sband->channels[i];
				if (chan->flags & (IEEE80211_CHAN_NO_IR |
						   IEEE80211_CHAN_DISABLED |
						   IEEE80211_CHAN_RADAR))
					continue;
				setup->chandef.chan = chan;
				break;
			}

			if (setup->chandef.chan)
				break;
		}

		/* no usable channel ... */
		if (!setup->chandef.chan)
			return -EINVAL;

		setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
		setup->chandef.center_freq1 = setup->chandef.chan->center_freq;
	}

	/*
	 * check if basic rates are available otherwise use mandatory rates as
	 * basic rates
	 */
	if (!setup->basic_rates) {
		enum nl80211_bss_scan_width scan_width;
		struct ieee80211_supported_band *sband =
				rdev->wiphy.bands[setup->chandef.chan->band];
		scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
		setup->basic_rates = ieee80211_mandatory_rates(sband,
							       scan_width);
	}

	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
				     NL80211_IFTYPE_MESH_POINT))
		return -EINVAL;

	err = rdev_join_mesh(rdev, dev, conf, setup);
	if (!err) {
		memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
		wdev->mesh_id_len = setup->mesh_id_len;
		wdev->chandef = setup->chandef;
	}

	return err;
}
Beispiel #2
0
int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
			 struct net_device *dev,
			 struct mesh_setup *setup,
			 const struct mesh_config *conf)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

	BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);

	ASSERT_WDEV_LOCK(wdev);

	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
		return -EOPNOTSUPP;

	if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
	      setup->is_secure)
		return -EOPNOTSUPP;

	if (wdev->mesh_id_len)
		return -EALREADY;

	if (!setup->mesh_id_len)
		return -EINVAL;

	if (!rdev->ops->join_mesh)
		return -EOPNOTSUPP;

	if (!setup->chandef.chan) {
		/* if no channel explicitly given, use preset channel */
		setup->chandef = wdev->preset_chandef;
	}

	if (!setup->chandef.chan) {
		/* if we don't have that either, use the first usable channel */
		enum nl80211_band band;

		for (band = 0; band < NUM_NL80211_BANDS; band++) {
			struct ieee80211_supported_band *sband;
			struct ieee80211_channel *chan;
			int i;

			sband = rdev->wiphy.bands[band];
			if (!sband)
				continue;

			for (i = 0; i < sband->n_channels; i++) {
				chan = &sband->channels[i];
				if (chan->flags & (IEEE80211_CHAN_NO_IR |
						   IEEE80211_CHAN_DISABLED |
						   IEEE80211_CHAN_RADAR))
					continue;
				setup->chandef.chan = chan;
				break;
			}

			if (setup->chandef.chan)
				break;
		}

		/* no usable channel ... */
		if (!setup->chandef.chan)
			return -EINVAL;

		setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
		setup->chandef.center_freq1 = setup->chandef.chan->center_freq;
	}

	/*
	 * check if basic rates are available otherwise use mandatory rates as
	 * basic rates
	 */
	if (!setup->basic_rates) {
		enum nl80211_bss_scan_width scan_width;
		struct ieee80211_supported_band *sband =
				rdev->wiphy.bands[setup->chandef.chan->band];

		if (setup->chandef.chan->band == NL80211_BAND_2GHZ) {
			int i;

			/*
			 * Older versions selected the mandatory rates for
			 * 2.4 GHz as well, but were broken in that only
			 * 1 Mbps was regarded as a mandatory rate. Keep
			 * using just 1 Mbps as the default basic rate for
			 * mesh to be interoperable with older versions.
			 */
			for (i = 0; i < sband->n_bitrates; i++) {
				if (sband->bitrates[i].bitrate == 10) {
					setup->basic_rates = BIT(i);
					break;
				}
			}
		} else {
			scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
			setup->basic_rates = ieee80211_mandatory_rates(sband,
								       scan_width);
		}
	}

	err = cfg80211_chandef_dfs_required(&rdev->wiphy,
					    &setup->chandef,
					    NL80211_IFTYPE_MESH_POINT);
	if (err < 0)
		return err;
	if (err > 0 && !setup->userspace_handles_dfs)
		return -EINVAL;

	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
				     NL80211_IFTYPE_MESH_POINT))
		return -EINVAL;

	err = rdev_join_mesh(rdev, dev, conf, setup);
	if (!err) {
		memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
		wdev->mesh_id_len = setup->mesh_id_len;
		wdev->chandef = setup->chandef;
		wdev->beacon_interval = setup->beacon_interval;
	}

	return err;
}