mesh.c 7.4 KB
Newer Older
1
#include <linux/ieee80211.h>
2
#include <linux/export.h>
3
#include <net/cfg80211.h>
4
#include "nl80211.h"
5
#include "core.h"
6
#include "rdev-ops.h"
7 8 9 10 11 12 13 14 15 16

/* Default values, timeouts in ms */
#define MESH_TTL 		31
#define MESH_DEFAULT_ELEMENT_TTL 31
#define MESH_MAX_RETR	 	3
#define MESH_RET_T 		100
#define MESH_CONF_T 		100
#define MESH_HOLD_T 		100

#define MESH_PATH_TIMEOUT	5000
17
#define MESH_RANN_INTERVAL      5000
18 19
#define MESH_PATH_TO_ROOT_TIMEOUT      6000
#define MESH_ROOT_INTERVAL     5000
20
#define MESH_ROOT_CONFIRMATION_INTERVAL 2000
21 22 23 24 25 26

/*
 * Minimum interval between two consecutive PREQs originated by the same
 * interface
 */
#define MESH_PREQ_MIN_INT	10
27
#define MESH_PERR_MIN_INT	100
28 29
#define MESH_DIAM_TRAVERSAL_TIME 50

30 31
#define MESH_RSSI_THRESHOLD	0

32 33 34 35 36 37 38 39 40 41 42 43 44
/*
 * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds
 * before timing out.  This way it will remain ACTIVE and no data frames
 * will be unnecessarily held in the pending queue.
 */
#define MESH_PATH_REFRESH_TIME			1000
#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)

/* Default maximum number of established plinks per interface */
#define MESH_MAX_ESTAB_PLINKS	32

#define MESH_MAX_PREQ_RETRIES	4

45
#define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50
46 47 48 49 50 51 52 53 54 55

const struct mesh_config default_mesh_config = {
	.dot11MeshRetryTimeout = MESH_RET_T,
	.dot11MeshConfirmTimeout = MESH_CONF_T,
	.dot11MeshHoldingTimeout = MESH_HOLD_T,
	.dot11MeshMaxRetries = MESH_MAX_RETR,
	.dot11MeshTTL = MESH_TTL,
	.element_ttl = MESH_DEFAULT_ELEMENT_TTL,
	.auto_open_plinks = true,
	.dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS,
56
	.dot11MeshNbrOffsetMaxNeighbor = MESH_SYNC_NEIGHBOR_OFFSET_MAX,
57 58
	.dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT,
	.dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT,
59
	.dot11MeshHWMPperrMinInterval = MESH_PERR_MIN_INT,
60 61 62 63
	.dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME,
	.dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
	.path_refresh_time = MESH_PATH_REFRESH_TIME,
	.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
64
	.dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
65
	.dot11MeshGateAnnouncementProtocol = false,
66
	.dot11MeshForwarding = true,
67
	.rssi_threshold = MESH_RSSI_THRESHOLD,
68
	.ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED,
69 70
	.dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT,
	.dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL,
71
	.dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
72 73
};

74
const struct mesh_setup default_mesh_setup = {
75 76 77
	/* cfg80211_join_mesh() will pick a channel if needed */
	.channel = NULL,
	.channel_type = NL80211_CHAN_NO_HT,
78
	.sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
79 80
	.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
	.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
81 82
	.ie = NULL,
	.ie_len = 0,
83
	.is_secure = false,
84
};
85 86 87

int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
			 struct net_device *dev,
88
			 struct mesh_setup *setup,
89 90 91 92 93 94 95 96 97 98 99 100
			 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;

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

105 106 107
	if (wdev->mesh_id_len)
		return -EALREADY;

108
	if (!setup->mesh_id_len)
109 110 111 112 113
		return -EINVAL;

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

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	if (!setup->channel) {
		/* if no channel explicitly given, use preset channel */
		setup->channel = wdev->preset_chan;
		setup->channel_type = wdev->preset_chantype;
	}

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

		for (band = 0; band < IEEE80211_NUM_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_IBSS |
						   IEEE80211_CHAN_PASSIVE_SCAN |
						   IEEE80211_CHAN_DISABLED |
						   IEEE80211_CHAN_RADAR))
					continue;
				setup->channel = chan;
				break;
			}

			if (setup->channel)
				break;
		}

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

		setup->channel_type = NL80211_CHAN_NO_HT;
	}

	if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
					  setup->channel_type))
		return -EINVAL;

159 160 161 162 163
	err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
				    CHAN_MODE_SHARED);
	if (err)
		return err;

164
	err = rdev_join_mesh(rdev, dev, conf, setup);
165
	if (!err) {
166 167
		memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
		wdev->mesh_id_len = setup->mesh_id_len;
168
		wdev->channel = setup->channel;
169 170 171 172 173 174 175
	}

	return err;
}

int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
		       struct net_device *dev,
176
		       struct mesh_setup *setup,
177 178 179 180 181
		       const struct mesh_config *conf)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

182
	mutex_lock(&rdev->devlist_mtx);
183
	wdev_lock(wdev);
184
	err = __cfg80211_join_mesh(rdev, dev, setup, conf);
185
	wdev_unlock(wdev);
186
	mutex_unlock(&rdev->devlist_mtx);
187 188 189 190

	return err;
}

191 192 193 194 195
int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
			   struct wireless_dev *wdev, int freq,
			   enum nl80211_channel_type channel_type)
{
	struct ieee80211_channel *channel;
196
	int err;
197

198 199 200 201 202 203 204
	channel = rdev_freq_to_chan(rdev, freq, channel_type);
	if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
						      channel,
						      channel_type)) {
		return -EINVAL;
	}

205 206 207 208 209 210 211
	/*
	 * Workaround for libertas (only!), it puts the interface
	 * into mesh mode but doesn't implement join_mesh. Instead,
	 * it is configured via sysfs and then joins the mesh when
	 * you set the channel. Note that the libertas mesh isn't
	 * compatible with 802.11 mesh.
	 */
212 213 214
	if (rdev->ops->libertas_set_mesh_channel) {
		if (channel_type != NL80211_CHAN_NO_HT)
			return -EINVAL;
215 216 217

		if (!netif_running(wdev->netdev))
			return -ENETDOWN;
218

219 220 221 222 223
		err = cfg80211_can_use_chan(rdev, wdev, channel,
					    CHAN_MODE_SHARED);
		if (err)
			return err;

224 225
		err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
						     channel);
226 227 228 229
		if (!err)
			wdev->channel = channel;

		return err;
230 231 232 233 234 235 236 237 238 239
	}

	if (wdev->mesh_id_len)
		return -EBUSY;

	wdev->preset_chan = channel;
	wdev->preset_chantype = channel_type;
	return 0;
}

240 241 242 243 244 245 246 247 248 249 250 251 252
void cfg80211_notify_new_peer_candidate(struct net_device *dev,
		const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;

	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
		return;

	nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
			macaddr, ie, ie_len, gfp);
}
EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
				 struct net_device *dev)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

	ASSERT_WDEV_LOCK(wdev);

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

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

	if (!wdev->mesh_id_len)
		return -ENOTCONN;

270
	err = rdev_leave_mesh(rdev, dev);
271
	if (!err) {
272
		wdev->mesh_id_len = 0;
273 274 275
		wdev->channel = NULL;
	}

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
	return err;
}

int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
			struct net_device *dev)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	int err;

	wdev_lock(wdev);
	err = __cfg80211_leave_mesh(rdev, dev);
	wdev_unlock(wdev);

	return err;
}