mesh_hwmp.c 34.0 KB
Newer Older
1
/*
R
Rui Paulo 已提交
2
 * Copyright (c) 2008, 2009 open80211s Ltd.
3 4 5 6 7 8 9
 * Author:     Luis Carlos Cobo <luisca@cozybit.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

10
#include <linux/slab.h>
11
#include <linux/etherdevice.h>
12
#include <asm/unaligned.h>
13
#include "wme.h"
14 15 16 17 18 19 20 21 22 23 24 25
#include "mesh.h"

#define TEST_FRAME_LEN	8192
#define MAX_METRIC	0xffffffff
#define ARITH_SHIFT	8

#define MAX_PREQ_QUEUE_LEN	64

/* Destination only */
#define MP_F_DO	0x1
/* Reply and forward */
#define MP_F_RF	0x2
R
Rui Paulo 已提交
26 27 28 29
/* Unknown Sequence Number */
#define MP_F_USN    0x01
/* Reason code Present */
#define MP_F_RCODE  0x02
30

31 32
static void mesh_queue_preq(struct mesh_path *, u8);

33 34 35 36
static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
{
	if (ae)
		offset += 6;
37
	return get_unaligned_le32(preq_elem + offset);
38 39
}

R
Rui Paulo 已提交
40 41 42 43 44 45 46
static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
{
	if (ae)
		offset += 6;
	return get_unaligned_le16(preq_elem + offset);
}

47
/* HWMP IE processing macros */
48 49 50 51 52 53 54
#define AE_F			(1<<6)
#define AE_F_SET(x)		(*x & AE_F)
#define PREQ_IE_FLAGS(x)	(*(x))
#define PREQ_IE_HOPCOUNT(x)	(*(x + 1))
#define PREQ_IE_TTL(x)		(*(x + 2))
#define PREQ_IE_PREQ_ID(x)	u32_field_get(x, 3, 0)
#define PREQ_IE_ORIG_ADDR(x)	(x + 7)
55 56 57
#define PREQ_IE_ORIG_SN(x)	u32_field_get(x, 13, 0)
#define PREQ_IE_LIFETIME(x)	u32_field_get(x, 17, AE_F_SET(x))
#define PREQ_IE_METRIC(x) 	u32_field_get(x, 21, AE_F_SET(x))
58 59
#define PREQ_IE_TARGET_F(x)	(*(AE_F_SET(x) ? x + 32 : x + 26))
#define PREQ_IE_TARGET_ADDR(x) 	(AE_F_SET(x) ? x + 33 : x + 27)
60
#define PREQ_IE_TARGET_SN(x) 	u32_field_get(x, 33, AE_F_SET(x))
61 62 63 64 65


#define PREP_IE_FLAGS(x)	PREQ_IE_FLAGS(x)
#define PREP_IE_HOPCOUNT(x)	PREQ_IE_HOPCOUNT(x)
#define PREP_IE_TTL(x)		PREQ_IE_TTL(x)
66 67
#define PREP_IE_ORIG_ADDR(x)	(AE_F_SET(x) ? x + 27 : x + 21)
#define PREP_IE_ORIG_SN(x)	u32_field_get(x, 27, AE_F_SET(x))
68 69
#define PREP_IE_LIFETIME(x)	u32_field_get(x, 13, AE_F_SET(x))
#define PREP_IE_METRIC(x)	u32_field_get(x, 17, AE_F_SET(x))
70 71
#define PREP_IE_TARGET_ADDR(x)	(x + 3)
#define PREP_IE_TARGET_SN(x)	u32_field_get(x, 9, 0)
72

R
Rui Paulo 已提交
73
#define PERR_IE_TTL(x)		(*(x))
74 75
#define PERR_IE_TARGET_FLAGS(x)	(*(x + 2))
#define PERR_IE_TARGET_ADDR(x)	(x + 3)
76 77
#define PERR_IE_TARGET_SN(x)	u32_field_get(x, 9, 0)
#define PERR_IE_TARGET_RCODE(x)	u16_field_get(x, 13, 0)
78 79

#define MSEC_TO_TU(x) (x*1000/1024)
80 81
#define SN_GT(x, y) ((s32)(y - x) < 0)
#define SN_LT(x, y) ((s32)(x - y) < 0)
82 83

#define net_traversal_jiffies(s) \
84
	msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
85
#define default_lifetime(s) \
86
	MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout)
87
#define min_preq_int_jiff(s) \
88 89
	(msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval))
#define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)
90
#define disc_timeout_jiff(s) \
91
	msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
92 93
#define root_path_confirmation_jiffies(s) \
	msecs_to_jiffies(sdata->u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval)
94 95 96 97

enum mpath_frame_type {
	MPATH_PREQ = 0,
	MPATH_PREP,
98 99
	MPATH_PERR,
	MPATH_RANN
100 101
};

102 103
static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

104
static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
105
		u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
106 107
		__le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
		__le32 lifetime, __le32 metric, __le32 preq_id,
108
		struct ieee80211_sub_if_data *sdata)
109
{
110
	struct ieee80211_local *local = sdata->local;
111
	struct sk_buff *skb;
112
	struct ieee80211_mgmt *mgmt;
113 114 115
	u8 *pos, ie_len;
	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
		      sizeof(mgmt->u.action.u.mesh_action);
116

117
	skb = dev_alloc_skb(local->tx_headroom +
118 119
			    hdr_len +
			    2 + 37); /* max HWMP IE */
120 121
	if (!skb)
		return -1;
122
	skb_reserve(skb, local->tx_headroom);
123 124
	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
	memset(mgmt, 0, hdr_len);
125 126
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_ACTION);
127 128

	memcpy(mgmt->da, da, ETH_ALEN);
129
	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
130
	/* BSSID == SA */
131
	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
132 133 134
	mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
	mgmt->u.action.u.mesh_action.action_code =
					WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
135 136 137

	switch (action) {
	case MPATH_PREQ:
J
Johannes Berg 已提交
138
		mhwmp_dbg(sdata, "sending PREQ to %pM\n", target);
139 140 141 142 143
		ie_len = 37;
		pos = skb_put(skb, 2 + ie_len);
		*pos++ = WLAN_EID_PREQ;
		break;
	case MPATH_PREP:
J
Johannes Berg 已提交
144
		mhwmp_dbg(sdata, "sending PREP to %pM\n", target);
145 146 147 148
		ie_len = 31;
		pos = skb_put(skb, 2 + ie_len);
		*pos++ = WLAN_EID_PREP;
		break;
149
	case MPATH_RANN:
J
Johannes Berg 已提交
150
		mhwmp_dbg(sdata, "sending RANN from %pM\n", orig_addr);
151 152 153 154
		ie_len = sizeof(struct ieee80211_rann_ie);
		pos = skb_put(skb, 2 + ie_len);
		*pos++ = WLAN_EID_RANN;
		break;
155
	default:
156
		kfree_skb(skb);
157 158 159 160 161 162 163
		return -ENOTSUPP;
		break;
	}
	*pos++ = ie_len;
	*pos++ = flags;
	*pos++ = hop_count;
	*pos++ = ttl;
164 165 166 167
	if (action == MPATH_PREP) {
		memcpy(pos, target, ETH_ALEN);
		pos += ETH_ALEN;
		memcpy(pos, &target_sn, 4);
168
		pos += 4;
169 170 171 172 173 174 175 176
	} else {
		if (action == MPATH_PREQ) {
			memcpy(pos, &preq_id, 4);
			pos += 4;
		}
		memcpy(pos, orig_addr, ETH_ALEN);
		pos += ETH_ALEN;
		memcpy(pos, &orig_sn, 4);
177 178
		pos += 4;
	}
179 180
	memcpy(pos, &lifetime, 4);	/* interval for RANN */
	pos += 4;
181 182 183
	memcpy(pos, &metric, 4);
	pos += 4;
	if (action == MPATH_PREQ) {
184
		*pos++ = 1; /* destination count */
185 186
		*pos++ = target_flags;
		memcpy(pos, target, ETH_ALEN);
187
		pos += ETH_ALEN;
188
		memcpy(pos, &target_sn, 4);
189 190 191 192 193 194
		pos += 4;
	} else if (action == MPATH_PREP) {
		memcpy(pos, orig_addr, ETH_ALEN);
		pos += ETH_ALEN;
		memcpy(pos, &orig_sn, 4);
		pos += 4;
195
	}
196

197
	ieee80211_tx_skb(sdata, skb);
198 199 200
	return 0;
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217

/*  Headroom is not adjusted.  Caller should ensure that skb has sufficient
 *  headroom in case the frame is encrypted. */
static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
		struct sk_buff *skb)
{
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);

	skb_set_mac_header(skb, 0);
	skb_set_network_header(skb, 0);
	skb_set_transport_header(skb, 0);

	/* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
	skb_set_queue_mapping(skb, IEEE80211_AC_VO);
	skb->priority = 7;

	info->control.vif = &sdata->vif;
218
	ieee80211_set_qos_hdr(sdata, skb);
219 220
}

221 222 223
/**
 * mesh_send_path error - Sends a PERR mesh management frame
 *
224 225 226
 * @target: broken destination
 * @target_sn: SN of the broken destination
 * @target_rcode: reason code for this PERR
227
 * @ra: node this frame is addressed to
228 229 230 231
 *
 * Note: This function may be called with driver locks taken that the driver
 * also acquires in the TX path.  To avoid a deadlock we don't transmit the
 * frame directly but add it to the pending queue instead.
232
 */
233
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
234 235
		       __le16 target_rcode, const u8 *ra,
		       struct ieee80211_sub_if_data *sdata)
236
{
237
	struct ieee80211_local *local = sdata->local;
238
	struct sk_buff *skb;
239
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
240
	struct ieee80211_mgmt *mgmt;
241 242 243
	u8 *pos, ie_len;
	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
		      sizeof(mgmt->u.action.u.mesh_action);
244

245 246 247
	if (time_before(jiffies, ifmsh->next_perr))
		return -EAGAIN;

248
	skb = dev_alloc_skb(local->tx_headroom +
249 250
			    hdr_len +
			    2 + 15 /* PERR IE */);
251 252
	if (!skb)
		return -1;
253
	skb_reserve(skb, local->tx_headroom);
254 255
	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
	memset(mgmt, 0, hdr_len);
256 257
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_ACTION);
258 259

	memcpy(mgmt->da, ra, ETH_ALEN);
260
	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
261 262 263 264 265
	/* BSSID == SA */
	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
	mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
	mgmt->u.action.u.mesh_action.action_code =
					WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
R
Rui Paulo 已提交
266
	ie_len = 15;
267 268 269
	pos = skb_put(skb, 2 + ie_len);
	*pos++ = WLAN_EID_PERR;
	*pos++ = ie_len;
R
Rui Paulo 已提交
270
	/* ttl */
271
	*pos++ = ttl;
272 273
	/* number of destinations */
	*pos++ = 1;
R
Rui Paulo 已提交
274 275 276 277 278
	/*
	 * flags bit, bit 1 is unset if we know the sequence number and
	 * bit 2 is set if we have a reason code
	 */
	*pos = 0;
279
	if (!target_sn)
R
Rui Paulo 已提交
280
		*pos |= MP_F_USN;
281
	if (target_rcode)
R
Rui Paulo 已提交
282 283
		*pos |= MP_F_RCODE;
	pos++;
284
	memcpy(pos, target, ETH_ALEN);
285
	pos += ETH_ALEN;
286
	memcpy(pos, &target_sn, 4);
R
Rui Paulo 已提交
287
	pos += 4;
288
	memcpy(pos, &target_rcode, 2);
289

290 291
	/* see note in function header */
	prepare_frame_for_deferred_tx(sdata, skb);
292 293
	ifmsh->next_perr = TU_TO_EXP_TIME(
				   ifmsh->mshcfg.dot11MeshHWMPperrMinInterval);
294
	ieee80211_add_pending_skb(local, skb);
295 296 297
	return 0;
}

298
void ieee80211s_update_metric(struct ieee80211_local *local,
299
		struct sta_info *sta, struct sk_buff *skb)
300 301 302 303 304 305 306 307 308 309 310
{
	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	int failed;

	if (!ieee80211_is_data(hdr->frame_control))
		return;

	failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);

	/* moving average, scaled to 100 */
311 312 313
	sta->fail_avg = ((80 * sta->fail_avg + 5) / 100 + 20 * failed);
	if (sta->fail_avg > 95)
		mesh_plink_broken(sta);
314 315
}

316 317 318
static u32 airtime_link_metric_get(struct ieee80211_local *local,
				   struct sta_info *sta)
{
319
	struct rate_info rinfo;
320 321 322 323 324 325 326 327 328 329
	/* This should be adjusted for each device */
	int device_constant = 1 << ARITH_SHIFT;
	int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT;
	int s_unit = 1 << ARITH_SHIFT;
	int rate, err;
	u32 tx_time, estimated_retx;
	u64 result;

	if (sta->fail_avg >= 100)
		return MAX_METRIC;
330

331 332 333
	sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo);
	rate = cfg80211_calculate_bitrate(&rinfo);
	if (WARN_ON(!rate))
334 335
		return MAX_METRIC;

336 337 338 339 340 341 342 343 344 345 346 347 348 349
	err = (sta->fail_avg << ARITH_SHIFT) / 100;

	/* bitrate is in units of 100 Kbps, while we need rate in units of
	 * 1Mbps. This will be corrected on tx_time computation.
	 */
	tx_time = (device_constant + 10 * test_frame_len / rate);
	estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
	result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
	return (u32)result;
}

/**
 * hwmp_route_info_get - Update routing info to originator and transmitter
 *
350
 * @sdata: local mesh subif
351 352 353 354
 * @mgmt: mesh management frame
 * @hwmp_ie: hwmp information element (PREP or PREQ)
 *
 * This function updates the path routing information to the originator and the
355
 * transmitter of a HWMP PREQ or PREP frame.
356 357 358 359 360 361 362
 *
 * Returns: metric to frame originator or 0 if the frame should not be further
 * processed
 *
 * Notes: this function is the only place (besides user-provided info) where
 * path routing information is updated.
 */
363
static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
364
			    struct ieee80211_mgmt *mgmt,
365
			    u8 *hwmp_ie, enum mpath_frame_type action)
366
{
367
	struct ieee80211_local *local = sdata->local;
368 369 370 371
	struct mesh_path *mpath;
	struct sta_info *sta;
	bool fresh_info;
	u8 *orig_addr, *ta;
372
	u32 orig_sn, orig_metric;
373 374 375 376 377
	unsigned long orig_lifetime, exp_time;
	u32 last_hop_metric, new_metric;
	bool process = true;

	rcu_read_lock();
378
	sta = sta_info_get(sdata, mgmt->sa);
379 380
	if (!sta) {
		rcu_read_unlock();
381
		return 0;
382
	}
383 384 385 386 387 388 389 390

	last_hop_metric = airtime_link_metric_get(local, sta);
	/* Update and check originator routing info */
	fresh_info = true;

	switch (action) {
	case MPATH_PREQ:
		orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie);
391
		orig_sn = PREQ_IE_ORIG_SN(hwmp_ie);
392 393 394 395
		orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
		orig_metric = PREQ_IE_METRIC(hwmp_ie);
		break;
	case MPATH_PREP:
396 397
		/* Originator here refers to the MP that was the target in the
		 * Path Request. We divert from the nomenclature in the draft
398 399 400
		 * so that we can easily use a single function to gather path
		 * information from both PREQ and PREP frames.
		 */
401 402
		orig_addr = PREP_IE_TARGET_ADDR(hwmp_ie);
		orig_sn = PREP_IE_TARGET_SN(hwmp_ie);
403 404 405 406
		orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
		orig_metric = PREP_IE_METRIC(hwmp_ie);
		break;
	default:
407
		rcu_read_unlock();
408 409 410 411 412 413 414
		return 0;
	}
	new_metric = orig_metric + last_hop_metric;
	if (new_metric < orig_metric)
		new_metric = MAX_METRIC;
	exp_time = TU_TO_EXP_TIME(orig_lifetime);

415
	if (ether_addr_equal(orig_addr, sdata->vif.addr)) {
416 417 418 419 420 421
		/* This MP is the originator, we are not interested in this
		 * frame, except for updating transmitter's path info.
		 */
		process = false;
		fresh_info = false;
	} else {
422
		mpath = mesh_path_lookup(orig_addr, sdata);
423 424 425 426 427
		if (mpath) {
			spin_lock_bh(&mpath->state_lock);
			if (mpath->flags & MESH_PATH_FIXED)
				fresh_info = false;
			else if ((mpath->flags & MESH_PATH_ACTIVE) &&
428 429 430
			    (mpath->flags & MESH_PATH_SN_VALID)) {
				if (SN_GT(mpath->sn, orig_sn) ||
				    (mpath->sn == orig_sn &&
431
				     new_metric >= mpath->metric)) {
432 433 434 435 436
					process = false;
					fresh_info = false;
				}
			}
		} else {
437 438
			mesh_path_add(orig_addr, sdata);
			mpath = mesh_path_lookup(orig_addr, sdata);
439 440 441 442 443 444 445 446 447
			if (!mpath) {
				rcu_read_unlock();
				return 0;
			}
			spin_lock_bh(&mpath->state_lock);
		}

		if (fresh_info) {
			mesh_path_assign_nexthop(mpath, sta);
448
			mpath->flags |= MESH_PATH_SN_VALID;
449
			mpath->metric = new_metric;
450
			mpath->sn = orig_sn;
451 452 453 454 455 456 457 458 459 460 461 462 463 464
			mpath->exp_time = time_after(mpath->exp_time, exp_time)
					  ?  mpath->exp_time : exp_time;
			mesh_path_activate(mpath);
			spin_unlock_bh(&mpath->state_lock);
			mesh_path_tx_pending(mpath);
			/* draft says preq_id should be saved to, but there does
			 * not seem to be any use for it, skipping by now
			 */
		} else
			spin_unlock_bh(&mpath->state_lock);
	}

	/* Update and check transmitter routing info */
	ta = mgmt->sa;
465
	if (ether_addr_equal(orig_addr, ta))
466 467 468 469
		fresh_info = false;
	else {
		fresh_info = true;

470
		mpath = mesh_path_lookup(ta, sdata);
471 472 473 474 475 476 477
		if (mpath) {
			spin_lock_bh(&mpath->state_lock);
			if ((mpath->flags & MESH_PATH_FIXED) ||
				((mpath->flags & MESH_PATH_ACTIVE) &&
					(last_hop_metric > mpath->metric)))
				fresh_info = false;
		} else {
478 479
			mesh_path_add(ta, sdata);
			mpath = mesh_path_lookup(ta, sdata);
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
			if (!mpath) {
				rcu_read_unlock();
				return 0;
			}
			spin_lock_bh(&mpath->state_lock);
		}

		if (fresh_info) {
			mesh_path_assign_nexthop(mpath, sta);
			mpath->metric = last_hop_metric;
			mpath->exp_time = time_after(mpath->exp_time, exp_time)
					  ?  mpath->exp_time : exp_time;
			mesh_path_activate(mpath);
			spin_unlock_bh(&mpath->state_lock);
			mesh_path_tx_pending(mpath);
		} else
			spin_unlock_bh(&mpath->state_lock);
	}

	rcu_read_unlock();

	return process ? new_metric : 0;
}

504
static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
505
				    struct ieee80211_mgmt *mgmt,
506 507
				    u8 *preq_elem, u32 metric)
{
508
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
509
	struct mesh_path *mpath = NULL;
510
	u8 *target_addr, *orig_addr;
511
	const u8 *da;
512 513
	u8 target_flags, ttl, flags;
	u32 orig_sn, target_sn, lifetime, orig_metric;
514 515
	bool reply = false;
	bool forward = true;
516
	bool root_is_gate;
517

518 519
	/* Update target SN, if present */
	target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
520
	orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
521 522 523
	target_sn = PREQ_IE_TARGET_SN(preq_elem);
	orig_sn = PREQ_IE_ORIG_SN(preq_elem);
	target_flags = PREQ_IE_TARGET_F(preq_elem);
524 525 526 527
	orig_metric = metric;
	/* Proactive PREQ gate announcements */
	flags = PREQ_IE_FLAGS(preq_elem);
	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
528

J
Johannes Berg 已提交
529
	mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr);
530

531
	if (ether_addr_equal(target_addr, sdata->vif.addr)) {
J
Johannes Berg 已提交
532
		mhwmp_dbg(sdata, "PREQ is for us\n");
533 534 535
		forward = false;
		reply = true;
		metric = 0;
536
		if (time_after(jiffies, ifmsh->last_sn_update +
537
					net_traversal_jiffies(sdata)) ||
538 539 540
		    time_before(jiffies, ifmsh->last_sn_update)) {
			target_sn = ++ifmsh->sn;
			ifmsh->last_sn_update = jiffies;
541
		}
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
	} else if (is_broadcast_ether_addr(target_addr) &&
		   (target_flags & IEEE80211_PREQ_TO_FLAG)) {
		rcu_read_lock();
		mpath = mesh_path_lookup(orig_addr, sdata);
		if (mpath) {
			if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
				reply = true;
				target_addr = sdata->vif.addr;
				target_sn = ++ifmsh->sn;
				metric = 0;
				ifmsh->last_sn_update = jiffies;
			}
			if (root_is_gate)
				mesh_path_add_gate(mpath);
		}
		rcu_read_unlock();
558 559
	} else {
		rcu_read_lock();
560
		mpath = mesh_path_lookup(target_addr, sdata);
561
		if (mpath) {
562 563 564 565 566
			if ((!(mpath->flags & MESH_PATH_SN_VALID)) ||
					SN_LT(mpath->sn, target_sn)) {
				mpath->sn = target_sn;
				mpath->flags |= MESH_PATH_SN_VALID;
			} else if ((!(target_flags & MP_F_DO)) &&
567 568 569
					(mpath->flags & MESH_PATH_ACTIVE)) {
				reply = true;
				metric = mpath->metric;
570 571 572
				target_sn = mpath->sn;
				if (target_flags & MP_F_RF)
					target_flags |= MP_F_DO;
573 574 575 576 577 578 579 580 581
				else
					forward = false;
			}
		}
		rcu_read_unlock();
	}

	if (reply) {
		lifetime = PREQ_IE_LIFETIME(preq_elem);
582
		ttl = ifmsh->mshcfg.element_ttl;
583
		if (ttl != 0) {
J
Johannes Berg 已提交
584
			mhwmp_dbg(sdata, "replying to the PREQ\n");
585 586 587
			mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
				cpu_to_le32(orig_sn), 0, target_addr,
				cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
588
				cpu_to_le32(lifetime), cpu_to_le32(metric),
589
				0, sdata);
590
		} else {
591
			ifmsh->mshstats.dropped_frames_ttl++;
592
		}
593 594
	}

595
	if (forward && ifmsh->mshcfg.dot11MeshForwarding) {
596
		u32 preq_id;
597
		u8 hopcount;
598 599 600 601

		ttl = PREQ_IE_TTL(preq_elem);
		lifetime = PREQ_IE_LIFETIME(preq_elem);
		if (ttl <= 1) {
602
			ifmsh->mshstats.dropped_frames_ttl++;
603 604
			return;
		}
J
Johannes Berg 已提交
605
		mhwmp_dbg(sdata, "forwarding the PREQ from %pM\n", orig_addr);
606 607 608
		--ttl;
		preq_id = PREQ_IE_PREQ_ID(preq_elem);
		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
609 610
		da = (mpath && mpath->is_root) ?
			mpath->rann_snd_addr : broadcast_addr;
611 612 613 614 615 616 617

		if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
			target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
			target_sn = PREQ_IE_TARGET_SN(preq_elem);
			metric = orig_metric;
		}

618
		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
619
				cpu_to_le32(orig_sn), target_flags, target_addr,
620
				cpu_to_le32(target_sn), da,
621 622
				hopcount, ttl, cpu_to_le32(lifetime),
				cpu_to_le32(metric), cpu_to_le32(preq_id),
623
				sdata);
624 625 626 627
		if (!is_multicast_ether_addr(da))
			ifmsh->mshstats.fwded_unicast++;
		else
			ifmsh->mshstats.fwded_mcast++;
628
		ifmsh->mshstats.fwded_frames++;
629 630 631 632
	}
}


J
Johannes Berg 已提交
633 634 635 636 637 638 639 640
static inline struct sta_info *
next_hop_deref_protected(struct mesh_path *mpath)
{
	return rcu_dereference_protected(mpath->next_hop,
					 lockdep_is_held(&mpath->state_lock));
}


641
static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
642 643 644
				    struct ieee80211_mgmt *mgmt,
				    u8 *prep_elem, u32 metric)
{
645
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
646
	struct mesh_path *mpath;
647
	u8 *target_addr, *orig_addr;
648 649
	u8 ttl, hopcount, flags;
	u8 next_hop[ETH_ALEN];
650
	u32 target_sn, orig_sn, lifetime;
651

J
Johannes Berg 已提交
652 653
	mhwmp_dbg(sdata, "received PREP from %pM\n",
		  PREP_IE_ORIG_ADDR(prep_elem));
654

655
	orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
656
	if (ether_addr_equal(orig_addr, sdata->vif.addr))
657 658 659
		/* destination, no forwarding required */
		return;

660 661 662
	if (!ifmsh->mshcfg.dot11MeshForwarding)
		return;

663 664
	ttl = PREP_IE_TTL(prep_elem);
	if (ttl <= 1) {
665
		sdata->u.mesh.mshstats.dropped_frames_ttl++;
666 667 668 669
		return;
	}

	rcu_read_lock();
670
	mpath = mesh_path_lookup(orig_addr, sdata);
671 672 673 674 675 676 677 678
	if (mpath)
		spin_lock_bh(&mpath->state_lock);
	else
		goto fail;
	if (!(mpath->flags & MESH_PATH_ACTIVE)) {
		spin_unlock_bh(&mpath->state_lock);
		goto fail;
	}
J
Johannes Berg 已提交
679
	memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN);
680 681 682 683 684
	spin_unlock_bh(&mpath->state_lock);
	--ttl;
	flags = PREP_IE_FLAGS(prep_elem);
	lifetime = PREP_IE_LIFETIME(prep_elem);
	hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1;
685
	target_addr = PREP_IE_TARGET_ADDR(prep_elem);
686 687
	target_sn = PREP_IE_TARGET_SN(prep_elem);
	orig_sn = PREP_IE_ORIG_SN(prep_elem);
688 689

	mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
690
		cpu_to_le32(orig_sn), 0, target_addr,
691
		cpu_to_le32(target_sn), next_hop, hopcount,
692
		ttl, cpu_to_le32(lifetime), cpu_to_le32(metric),
693
		0, sdata);
694
	rcu_read_unlock();
695 696

	sdata->u.mesh.mshstats.fwded_unicast++;
697
	sdata->u.mesh.mshstats.fwded_frames++;
698 699 700 701
	return;

fail:
	rcu_read_unlock();
702
	sdata->u.mesh.mshstats.dropped_frames_no_route++;
703 704
}

705
static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
706 707
			     struct ieee80211_mgmt *mgmt, u8 *perr_elem)
{
R
Rui Paulo 已提交
708
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
709
	struct mesh_path *mpath;
R
Rui Paulo 已提交
710
	u8 ttl;
711 712 713
	u8 *ta, *target_addr;
	u32 target_sn;
	u16 target_rcode;
714 715

	ta = mgmt->sa;
R
Rui Paulo 已提交
716 717 718 719 720 721
	ttl = PERR_IE_TTL(perr_elem);
	if (ttl <= 1) {
		ifmsh->mshstats.dropped_frames_ttl++;
		return;
	}
	ttl--;
722 723 724
	target_addr = PERR_IE_TARGET_ADDR(perr_elem);
	target_sn = PERR_IE_TARGET_SN(perr_elem);
	target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
R
Rui Paulo 已提交
725

726
	rcu_read_lock();
727
	mpath = mesh_path_lookup(target_addr, sdata);
728
	if (mpath) {
729 730
		struct sta_info *sta;

731
		spin_lock_bh(&mpath->state_lock);
732
		sta = next_hop_deref_protected(mpath);
733
		if (mpath->flags & MESH_PATH_ACTIVE &&
734
		    ether_addr_equal(ta, sta->sta.addr) &&
735 736
		    (!(mpath->flags & MESH_PATH_SN_VALID) ||
		    SN_GT(target_sn, mpath->sn))) {
737
			mpath->flags &= ~MESH_PATH_ACTIVE;
738
			mpath->sn = target_sn;
739
			spin_unlock_bh(&mpath->state_lock);
740 741
			if (!ifmsh->mshcfg.dot11MeshForwarding)
				goto endperr;
742 743
			mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
					   cpu_to_le16(target_rcode),
744
					   broadcast_addr, sdata);
745 746 747
		} else
			spin_unlock_bh(&mpath->state_lock);
	}
748
endperr:
749 750 751
	rcu_read_unlock();
}

752 753 754 755 756
static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
				struct ieee80211_mgmt *mgmt,
				struct ieee80211_rann_ie *rann)
{
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
757 758
	struct ieee80211_local *local = sdata->local;
	struct sta_info *sta;
759 760 761
	struct mesh_path *mpath;
	u8 ttl, flags, hopcount;
	u8 *orig_addr;
762
	u32 orig_sn, metric, metric_txsta, interval;
763
	bool root_is_gate;
764 765 766

	ttl = rann->rann_ttl;
	flags = rann->rann_flags;
767
	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
768
	orig_addr = rann->rann_addr;
769
	orig_sn = le32_to_cpu(rann->rann_seq);
770
	interval = le32_to_cpu(rann->rann_interval);
771
	hopcount = rann->rann_hopcount;
R
Rui Paulo 已提交
772
	hopcount++;
773
	metric = le32_to_cpu(rann->rann_metric);
774 775

	/*  Ignore our own RANNs */
776
	if (ether_addr_equal(orig_addr, sdata->vif.addr))
777 778
		return;

J
Johannes Berg 已提交
779 780 781
	mhwmp_dbg(sdata,
		  "received RANN from %pM via neighbour %pM (is_gate=%d)\n",
		  orig_addr, mgmt->sa, root_is_gate);
782 783

	rcu_read_lock();
784 785 786 787 788 789 790 791
	sta = sta_info_get(sdata, mgmt->sa);
	if (!sta) {
		rcu_read_unlock();
		return;
	}

	metric_txsta = airtime_link_metric_get(local, sta);

792 793 794 795 796 797 798 799 800 801
	mpath = mesh_path_lookup(orig_addr, sdata);
	if (!mpath) {
		mesh_path_add(orig_addr, sdata);
		mpath = mesh_path_lookup(orig_addr, sdata);
		if (!mpath) {
			rcu_read_unlock();
			sdata->u.mesh.mshstats.dropped_frames_no_route++;
			return;
		}
	}
802

803 804 805 806 807 808
	if (!(SN_LT(mpath->sn, orig_sn)) &&
	    !(mpath->sn == orig_sn && metric < mpath->rann_metric)) {
		rcu_read_unlock();
		return;
	}

809
	if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
810 811 812
	     (time_after(jiffies, mpath->last_preq_to_root +
				  root_path_confirmation_jiffies(sdata)) ||
	     time_before(jiffies, mpath->last_preq_to_root))) &&
813
	     !(mpath->flags & MESH_PATH_FIXED) && (ttl != 0)) {
J
Johannes Berg 已提交
814 815 816
		mhwmp_dbg(sdata,
			  "time to refresh root mpath %pM\n",
			  orig_addr);
817
		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
818
		mpath->last_preq_to_root = jiffies;
819 820
	}

821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
	mpath->sn = orig_sn;
	mpath->rann_metric = metric + metric_txsta;
	mpath->is_root = true;
	/* Recording RANNs sender address to send individually
	 * addressed PREQs destined for root mesh STA */
	memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);

	if (root_is_gate)
		mesh_path_add_gate(mpath);

	if (ttl <= 1) {
		ifmsh->mshstats.dropped_frames_ttl++;
		rcu_read_unlock();
		return;
	}
	ttl--;

	if (ifmsh->mshcfg.dot11MeshForwarding) {
839
		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
840
				       cpu_to_le32(orig_sn),
841
				       0, NULL, 0, broadcast_addr,
842
				       hopcount, ttl, cpu_to_le32(interval),
843
				       cpu_to_le32(metric + metric_txsta),
844 845
				       0, sdata);
	}
846

847 848
	rcu_read_unlock();
}
849 850


851
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
852 853 854 855 856 857
			    struct ieee80211_mgmt *mgmt,
			    size_t len)
{
	struct ieee802_11_elems elems;
	size_t baselen;
	u32 last_hop_metric;
858
	struct sta_info *sta;
859

860 861 862 863
	/* need action_code */
	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
		return;

864 865 866 867 868 869 870 871
	rcu_read_lock();
	sta = sta_info_get(sdata, mgmt->sa);
	if (!sta || sta->plink_state != NL80211_PLINK_ESTAB) {
		rcu_read_unlock();
		return;
	}
	rcu_read_unlock();

872 873 874 875
	baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
	ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
			len - baselen, &elems);

876 877
	if (elems.preq) {
		if (elems.preq_len != 37)
878 879
			/* Right now we support just 1 destination and no AE */
			return;
880 881 882 883 884 885 886 887
		last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
						      MPATH_PREQ);
		if (last_hop_metric)
			hwmp_preq_frame_process(sdata, mgmt, elems.preq,
						last_hop_metric);
	}
	if (elems.prep) {
		if (elems.prep_len != 31)
888 889
			/* Right now we support no AE */
			return;
890 891 892 893 894 895 896
		last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep,
						      MPATH_PREP);
		if (last_hop_metric)
			hwmp_prep_frame_process(sdata, mgmt, elems.prep,
						last_hop_metric);
	}
	if (elems.perr) {
R
Rui Paulo 已提交
897
		if (elems.perr_len != 15)
898 899
			/* Right now we support only one destination per PERR */
			return;
900
		hwmp_perr_frame_process(sdata, mgmt, elems.perr);
901
	}
902 903
	if (elems.rann)
		hwmp_rann_frame_process(sdata, mgmt, elems.rann);
904 905 906 907 908 909 910 911 912 913 914 915 916
}

/**
 * mesh_queue_preq - queue a PREQ to a given destination
 *
 * @mpath: mesh path to discover
 * @flags: special attributes of the PREQ to be sent
 *
 * Locking: the function must be called from within a rcu read lock block.
 *
 */
static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
{
917
	struct ieee80211_sub_if_data *sdata = mpath->sdata;
918
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
919 920
	struct mesh_preq_queue *preq_node;

921
	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
922
	if (!preq_node) {
J
Johannes Berg 已提交
923
		mhwmp_dbg(sdata, "could not allocate PREQ node\n");
924 925 926
		return;
	}

927
	spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
928
	if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
929
		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
930 931
		kfree(preq_node);
		if (printk_ratelimit())
J
Johannes Berg 已提交
932
			mhwmp_dbg(sdata, "PREQ node queue full\n");
933 934 935
		return;
	}

936
	spin_lock(&mpath->state_lock);
937
	if (mpath->flags & MESH_PATH_REQ_QUEUED) {
938
		spin_unlock(&mpath->state_lock);
939
		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
940
		kfree(preq_node);
941 942 943
		return;
	}

944 945 946
	memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
	preq_node->flags = flags;

947
	mpath->flags |= MESH_PATH_REQ_QUEUED;
948
	spin_unlock(&mpath->state_lock);
949

950 951
	list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
	++ifmsh->preq_queue_len;
952
	spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
953

954
	if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
J
Johannes Berg 已提交
955
		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
956

957
	else if (time_before(jiffies, ifmsh->last_preq)) {
958 959 960
		/* avoid long wait if did not send preqs for a long time
		 * and jiffies wrapped around
		 */
961
		ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
J
Johannes Berg 已提交
962
		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
963
	} else
964
		mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
965 966 967 968 969 970
						min_preq_int_jiff(sdata));
}

/**
 * mesh_path_start_discovery - launch a path discovery from the PREQ queue
 *
971
 * @sdata: local mesh subif
972
 */
973
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
974
{
975
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
976 977
	struct mesh_preq_queue *preq_node;
	struct mesh_path *mpath;
978
	u8 ttl, target_flags;
979
	const u8 *da;
980 981
	u32 lifetime;

982
	spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
983 984
	if (!ifmsh->preq_queue_len ||
		time_before(jiffies, ifmsh->last_preq +
985
				min_preq_int_jiff(sdata))) {
986
		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
987 988 989
		return;
	}

990
	preq_node = list_first_entry(&ifmsh->preq_queue.list,
991 992
			struct mesh_preq_queue, list);
	list_del(&preq_node->list);
993
	--ifmsh->preq_queue_len;
994
	spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
995 996

	rcu_read_lock();
997
	mpath = mesh_path_lookup(preq_node->dst, sdata);
998 999 1000 1001
	if (!mpath)
		goto enddiscovery;

	spin_lock_bh(&mpath->state_lock);
1002
	mpath->flags &= ~MESH_PATH_REQ_QUEUED;
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
	if (preq_node->flags & PREQ_Q_F_START) {
		if (mpath->flags & MESH_PATH_RESOLVING) {
			spin_unlock_bh(&mpath->state_lock);
			goto enddiscovery;
		} else {
			mpath->flags &= ~MESH_PATH_RESOLVED;
			mpath->flags |= MESH_PATH_RESOLVING;
			mpath->discovery_retries = 0;
			mpath->discovery_timeout = disc_timeout_jiff(sdata);
		}
	} else if (!(mpath->flags & MESH_PATH_RESOLVING) ||
			mpath->flags & MESH_PATH_RESOLVED) {
		mpath->flags &= ~MESH_PATH_RESOLVING;
		spin_unlock_bh(&mpath->state_lock);
		goto enddiscovery;
	}

1020
	ifmsh->last_preq = jiffies;
1021

1022
	if (time_after(jiffies, ifmsh->last_sn_update +
1023
				net_traversal_jiffies(sdata)) ||
1024 1025 1026
	    time_before(jiffies, ifmsh->last_sn_update)) {
		++ifmsh->sn;
		sdata->u.mesh.last_sn_update = jiffies;
1027 1028
	}
	lifetime = default_lifetime(sdata);
1029
	ttl = sdata->u.mesh.mshcfg.element_ttl;
1030
	if (ttl == 0) {
1031
		sdata->u.mesh.mshstats.dropped_frames_ttl++;
1032 1033 1034 1035 1036
		spin_unlock_bh(&mpath->state_lock);
		goto enddiscovery;
	}

	if (preq_node->flags & PREQ_Q_F_REFRESH)
1037
		target_flags = MP_F_DO;
1038
	else
1039
		target_flags = MP_F_RF;
1040 1041

	spin_unlock_bh(&mpath->state_lock);
1042
	da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr;
1043
	mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
1044
			cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
1045
			cpu_to_le32(mpath->sn), da, 0,
1046
			ttl, cpu_to_le32(lifetime), 0,
1047
			cpu_to_le32(ifmsh->preq_id++), sdata);
1048 1049 1050 1051 1052 1053 1054
	mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);

enddiscovery:
	rcu_read_unlock();
	kfree(preq_node);
}

1055 1056
/**
 * mesh_nexthop_resolve - lookup next hop; conditionally start path discovery
1057
 *
1058
 * @skb: 802.11 frame to be sent
1059
 * @sdata: network subif the frame will be sent through
1060
 *
1061 1062 1063
 * Lookup next hop for given skb and start path discovery if no
 * forwarding information is found.
 *
1064 1065
 * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
 * skb is freeed here if no mpath could be allocated.
1066
 */
1067 1068
int mesh_nexthop_resolve(struct sk_buff *skb,
			 struct ieee80211_sub_if_data *sdata)
1069
{
1070
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1071 1072 1073
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct mesh_path *mpath;
	struct sk_buff *skb_to_free = NULL;
1074
	u8 *target_addr = hdr->addr3;
1075 1076 1077
	int err = 0;

	rcu_read_lock();
1078 1079 1080
	err = mesh_nexthop_lookup(skb, sdata);
	if (!err)
		goto endlookup;
1081

1082 1083
	/* no nexthop found, start resolving */
	mpath = mesh_path_lookup(target_addr, sdata);
1084
	if (!mpath) {
1085 1086
		mesh_path_add(target_addr, sdata);
		mpath = mesh_path_lookup(target_addr, sdata);
1087
		if (!mpath) {
1088
			mesh_path_discard_frame(skb, sdata);
1089 1090 1091 1092 1093
			err = -ENOSPC;
			goto endlookup;
		}
	}

1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
	if (!(mpath->flags & MESH_PATH_RESOLVING))
		mesh_queue_preq(mpath, PREQ_Q_F_START);

	if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
		skb_to_free = skb_dequeue(&mpath->frame_queue);

	info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
	ieee80211_set_qos_hdr(sdata, skb);
	skb_queue_tail(&mpath->frame_queue, skb);
	err = -ENOENT;
	if (skb_to_free)
		mesh_path_discard_frame(skb_to_free, sdata);

endlookup:
	rcu_read_unlock();
	return err;
}
/**
 * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
 * this function is considered "using" the associated mpath, so preempt a path
 * refresh if this mpath expires soon.
 *
 * @skb: 802.11 frame to be sent
 * @sdata: network subif the frame will be sent through
 *
 * Returns: 0 if the next hop was found. Nonzero otherwise.
 */
int mesh_nexthop_lookup(struct sk_buff *skb,
			struct ieee80211_sub_if_data *sdata)
{
	struct mesh_path *mpath;
	struct sta_info *next_hop;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	u8 *target_addr = hdr->addr3;
	int err = -ENOENT;
1129

1130 1131 1132 1133 1134 1135 1136 1137 1138
	rcu_read_lock();
	mpath = mesh_path_lookup(target_addr, sdata);

	if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
		goto endlookup;

	if (time_after(jiffies,
		       mpath->exp_time -
		       msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
1139
	    ether_addr_equal(sdata->vif.addr, hdr->addr4) &&
1140 1141 1142
	    !(mpath->flags & MESH_PATH_RESOLVING) &&
	    !(mpath->flags & MESH_PATH_FIXED))
		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
1143

1144 1145 1146 1147 1148
	next_hop = rcu_dereference(mpath->next_hop);
	if (next_hop) {
		memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
		memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
		err = 0;
1149 1150 1151 1152 1153 1154 1155 1156 1157
	}

endlookup:
	rcu_read_unlock();
	return err;
}

void mesh_path_timer(unsigned long data)
{
1158 1159
	struct mesh_path *mpath = (void *) data;
	struct ieee80211_sub_if_data *sdata = mpath->sdata;
1160
	int ret;
1161

1162
	if (sdata->local->quiescing)
1163 1164 1165
		return;

	spin_lock_bh(&mpath->state_lock);
1166
	if (mpath->flags & MESH_PATH_RESOLVED ||
1167
			(!(mpath->flags & MESH_PATH_RESOLVING))) {
1168
		mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
1169 1170
		spin_unlock_bh(&mpath->state_lock);
	} else if (mpath->discovery_retries < max_preq_retries(sdata)) {
1171 1172
		++mpath->discovery_retries;
		mpath->discovery_timeout *= 2;
1173
		mpath->flags &= ~MESH_PATH_REQ_QUEUED;
1174
		spin_unlock_bh(&mpath->state_lock);
1175 1176 1177 1178
		mesh_queue_preq(mpath, 0);
	} else {
		mpath->flags = 0;
		mpath->exp_time = jiffies;
1179 1180 1181 1182
		spin_unlock_bh(&mpath->state_lock);
		if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
			ret = mesh_path_send_to_gates(mpath);
			if (ret)
J
Johannes Berg 已提交
1183
				mhwmp_dbg(sdata, "no gate was reachable\n");
1184 1185
		} else
			mesh_path_flush_pending(mpath);
1186 1187
	}
}
1188 1189 1190 1191 1192

void
mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
{
	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1193
	u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
1194
	u8 flags, target_flags = 0;
1195

1196 1197
	flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
			? RANN_FLAG_IS_GATE : 0;
1198 1199 1200 1201

	switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) {
	case IEEE80211_PROACTIVE_RANN:
		mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
1202
			       cpu_to_le32(++ifmsh->sn),
1203
			       0, NULL, 0, broadcast_addr,
1204
			       0, ifmsh->mshcfg.element_ttl,
1205
			       cpu_to_le32(interval), 0, 0, sdata);
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
		break;
	case IEEE80211_PROACTIVE_PREQ_WITH_PREP:
		flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG;
	case IEEE80211_PROACTIVE_PREQ_NO_PREP:
		interval = ifmsh->mshcfg.dot11MeshHWMPactivePathToRootTimeout;
		target_flags |= IEEE80211_PREQ_TO_FLAG |
				IEEE80211_PREQ_USN_FLAG;
		mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr,
				cpu_to_le32(++ifmsh->sn), target_flags,
				(u8 *) broadcast_addr, 0, broadcast_addr,
				0, ifmsh->mshcfg.element_ttl,
				cpu_to_le32(interval),
				0, cpu_to_le32(ifmsh->preq_id++), sdata);
		break;
	default:
J
Johannes Berg 已提交
1221
		mhwmp_dbg(sdata, "Proactive mechanism not supported\n");
1222 1223
		return;
	}
1224
}