Blame view

net/mac80211/mesh_hwmp.c 28.3 KB
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1
  /*
264d9b7d8   Rui Paulo   mac80211: update ...
2
   * Copyright (c) 2008, 2009 open80211s Ltd.
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
3
4
5
6
7
8
   * 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.
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
9
  #include <linux/slab.h>
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
10
  #include "mesh.h"
27db2e423   Rui Paulo   mac80211: add MAC...
11
12
13
14
15
  #ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
  #define mhwmp_dbg(fmt, args...)   printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args)
  #else
  #define mhwmp_dbg(fmt, args...)   do { (void)(0); } while (0)
  #endif
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
16
17
18
19
20
21
22
23
24
25
26
27
  #define TEST_FRAME_LEN	8192
  #define MAX_METRIC	0xffffffff
  #define ARITH_SHIFT	8
  
  /* Number of frames buffered per destination for unresolved destinations */
  #define MESH_FRAME_QUEUE_LEN	10
  #define MAX_PREQ_QUEUE_LEN	64
  
  /* Destination only */
  #define MP_F_DO	0x1
  /* Reply and forward */
  #define MP_F_RF	0x2
d611f062f   Rui Paulo   mac80211: update ...
28
29
30
31
  /* Unknown Sequence Number */
  #define MP_F_USN    0x01
  /* Reason code Present */
  #define MP_F_RCODE  0x02
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
32

90a5e1699   Rui Paulo   mac80211: impleme...
33
  static void mesh_queue_preq(struct mesh_path *, u8);
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
34
35
36
37
  static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
  {
  	if (ae)
  		offset += 6;
ae7245cbf   Harvey Harrison   wireless: use get...
38
  	return get_unaligned_le32(preq_elem + offset);
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
39
  }
d611f062f   Rui Paulo   mac80211: update ...
40
41
42
43
44
45
  static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
  {
  	if (ae)
  		offset += 6;
  	return get_unaligned_le16(preq_elem + offset);
  }
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
46
  /* HWMP IE processing macros */
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
47
48
49
50
51
52
53
  #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)
d19b3bf63   Rui Paulo   mac80211: replace...
54
  #define PREQ_IE_ORIG_SN(x)	u32_field_get(x, 13, 0);
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
55
56
  #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));
d19b3bf63   Rui Paulo   mac80211: replace...
57
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)
  #define PREQ_IE_TARGET_SN(x) 	u32_field_get(x, 33, AE_F_SET(x));
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
60
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)
  #define PREP_IE_ORIG_ADDR(x)	(x + 3)
d19b3bf63   Rui Paulo   mac80211: replace...
66
  #define PREP_IE_ORIG_SN(x)	u32_field_get(x, 9, 0);
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
67
68
  #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));
d19b3bf63   Rui Paulo   mac80211: replace...
69
70
  #define PREP_IE_TARGET_ADDR(x)	(AE_F_SET(x) ? x + 27 : x + 21)
  #define PREP_IE_TARGET_SN(x)	u32_field_get(x, 27, AE_F_SET(x));
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
71

d611f062f   Rui Paulo   mac80211: update ...
72
  #define PERR_IE_TTL(x)		(*(x))
d19b3bf63   Rui Paulo   mac80211: replace...
73
74
75
76
  #define PERR_IE_TARGET_FLAGS(x)	(*(x + 2))
  #define PERR_IE_TARGET_ADDR(x)	(x + 3)
  #define PERR_IE_TARGET_SN(x)	u32_field_get(x, 9, 0);
  #define PERR_IE_TARGET_RCODE(x)	u16_field_get(x, 13, 0);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
77

050ac52cb   Luis Carlos Cobo   mac80211: code fo...
78
  #define MSEC_TO_TU(x) (x*1000/1024)
d19b3bf63   Rui Paulo   mac80211: replace...
79
80
  #define SN_GT(x, y) ((long) (y) - (long) (x) < 0)
  #define SN_LT(x, y) ((long) (x) - (long) (y) < 0)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
81
82
  
  #define net_traversal_jiffies(s) \
472dbc45d   Johannes Berg   mac80211: split o...
83
  	msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
84
  #define default_lifetime(s) \
472dbc45d   Johannes Berg   mac80211: split o...
85
  	MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
86
  #define min_preq_int_jiff(s) \
472dbc45d   Johannes Berg   mac80211: split o...
87
88
  	(msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval))
  #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
89
  #define disc_timeout_jiff(s) \
472dbc45d   Johannes Berg   mac80211: split o...
90
  	msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
91
92
93
94
  
  enum mpath_frame_type {
  	MPATH_PREQ = 0,
  	MPATH_PREP,
90a5e1699   Rui Paulo   mac80211: impleme...
95
96
  	MPATH_PERR,
  	MPATH_RANN
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
97
  };
15ff63653   Johannes Berg   mac80211: use fix...
98
  static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
99
  static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
d19b3bf63   Rui Paulo   mac80211: replace...
100
  		u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
15ff63653   Johannes Berg   mac80211: use fix...
101
102
  		__le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
  		__le32 lifetime, __le32 metric, __le32 preq_id,
d19b3bf63   Rui Paulo   mac80211: replace...
103
  		struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
104
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
105
  	struct ieee80211_local *local = sdata->local;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
  	struct ieee80211_mgmt *mgmt;
  	u8 *pos;
  	int ie_len;
  
  	if (!skb)
  		return -1;
  	skb_reserve(skb, local->hw.extra_tx_headroom);
  	/* 25 is the size of the common mgmt part (24) plus the size of the
  	 * common action part (1)
  	 */
  	mgmt = (struct ieee80211_mgmt *)
  		skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
  	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
e7827a703   Harvey Harrison   mac80211: remove ...
120
121
  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					  IEEE80211_STYPE_ACTION);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
122
123
  
  	memcpy(mgmt->da, da, ETH_ALEN);
47846c9b0   Johannes Berg   mac80211: reduce ...
124
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
90a5e1699   Rui Paulo   mac80211: impleme...
125
  	/* BSSID == SA */
47846c9b0   Johannes Berg   mac80211: reduce ...
126
  	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
97ad9139f   Javier Cardona   mac80211: Moved m...
127
  	mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
095de0132   Rui Paulo   mac80211: update ...
128
  	mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
129
130
131
  
  	switch (action) {
  	case MPATH_PREQ:
d19b3bf63   Rui Paulo   mac80211: replace...
132
133
  		mhwmp_dbg("sending PREQ to %pM
  ", target);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
134
135
136
137
138
  		ie_len = 37;
  		pos = skb_put(skb, 2 + ie_len);
  		*pos++ = WLAN_EID_PREQ;
  		break;
  	case MPATH_PREP:
d19b3bf63   Rui Paulo   mac80211: replace...
139
140
  		mhwmp_dbg("sending PREP to %pM
  ", target);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
141
142
143
144
  		ie_len = 31;
  		pos = skb_put(skb, 2 + ie_len);
  		*pos++ = WLAN_EID_PREP;
  		break;
90a5e1699   Rui Paulo   mac80211: impleme...
145
146
147
148
149
150
151
  	case MPATH_RANN:
  		mhwmp_dbg("sending RANN from %pM
  ", orig_addr);
  		ie_len = sizeof(struct ieee80211_rann_ie);
  		pos = skb_put(skb, 2 + ie_len);
  		*pos++ = WLAN_EID_RANN;
  		break;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
152
  	default:
812714d74   Patrick McHardy   mac80211: mesh hw...
153
  		kfree_skb(skb);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
154
155
156
157
158
159
160
161
162
163
164
165
166
  		return -ENOTSUPP;
  		break;
  	}
  	*pos++ = ie_len;
  	*pos++ = flags;
  	*pos++ = hop_count;
  	*pos++ = ttl;
  	if (action == MPATH_PREQ) {
  		memcpy(pos, &preq_id, 4);
  		pos += 4;
  	}
  	memcpy(pos, orig_addr, ETH_ALEN);
  	pos += ETH_ALEN;
d19b3bf63   Rui Paulo   mac80211: replace...
167
  	memcpy(pos, &orig_sn, 4);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
168
  	pos += 4;
90a5e1699   Rui Paulo   mac80211: impleme...
169
170
171
172
  	if (action != MPATH_RANN) {
  		memcpy(pos, &lifetime, 4);
  		pos += 4;
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
173
174
175
176
177
  	memcpy(pos, &metric, 4);
  	pos += 4;
  	if (action == MPATH_PREQ) {
  		/* destination count */
  		*pos++ = 1;
d19b3bf63   Rui Paulo   mac80211: replace...
178
  		*pos++ = target_flags;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
179
  	}
90a5e1699   Rui Paulo   mac80211: impleme...
180
  	if (action != MPATH_RANN) {
d19b3bf63   Rui Paulo   mac80211: replace...
181
  		memcpy(pos, target, ETH_ALEN);
90a5e1699   Rui Paulo   mac80211: impleme...
182
  		pos += ETH_ALEN;
d19b3bf63   Rui Paulo   mac80211: replace...
183
  		memcpy(pos, &target_sn, 4);
90a5e1699   Rui Paulo   mac80211: impleme...
184
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
185

62ae67be3   Johannes Berg   mac80211: remove ...
186
  	ieee80211_tx_skb(sdata, skb);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
187
188
189
190
191
192
  	return 0;
  }
  
  /**
   * mesh_send_path error - Sends a PERR mesh management frame
   *
d19b3bf63   Rui Paulo   mac80211: replace...
193
194
195
   * @target: broken destination
   * @target_sn: SN of the broken destination
   * @target_rcode: reason code for this PERR
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
196
197
   * @ra: node this frame is addressed to
   */
d19b3bf63   Rui Paulo   mac80211: replace...
198
  int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
15ff63653   Johannes Berg   mac80211: use fix...
199
200
  		       __le16 target_rcode, const u8 *ra,
  		       struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
201
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
202
  	struct ieee80211_local *local = sdata->local;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
  	struct ieee80211_mgmt *mgmt;
  	u8 *pos;
  	int ie_len;
  
  	if (!skb)
  		return -1;
  	skb_reserve(skb, local->hw.extra_tx_headroom);
  	/* 25 is the size of the common mgmt part (24) plus the size of the
  	 * common action part (1)
  	 */
  	mgmt = (struct ieee80211_mgmt *)
  		skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
  	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
e7827a703   Harvey Harrison   mac80211: remove ...
217
218
  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					  IEEE80211_STYPE_ACTION);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
219
220
  
  	memcpy(mgmt->da, ra, ETH_ALEN);
47846c9b0   Johannes Berg   mac80211: reduce ...
221
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
222
  	/* BSSID is left zeroed, wildcard value */
97ad9139f   Javier Cardona   mac80211: Moved m...
223
  	mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
dbb81c428   Rui Paulo   mac80211: allow p...
224
  	mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
d611f062f   Rui Paulo   mac80211: update ...
225
  	ie_len = 15;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
226
227
228
  	pos = skb_put(skb, 2 + ie_len);
  	*pos++ = WLAN_EID_PERR;
  	*pos++ = ie_len;
d611f062f   Rui Paulo   mac80211: update ...
229
  	/* ttl */
45904f216   Javier Cardona   nl80211/mac80211:...
230
  	*pos++ = ttl;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
231
232
  	/* number of destinations */
  	*pos++ = 1;
d611f062f   Rui Paulo   mac80211: update ...
233
234
235
236
237
  	/*
  	 * 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;
d19b3bf63   Rui Paulo   mac80211: replace...
238
  	if (!target_sn)
d611f062f   Rui Paulo   mac80211: update ...
239
  		*pos |= MP_F_USN;
d19b3bf63   Rui Paulo   mac80211: replace...
240
  	if (target_rcode)
d611f062f   Rui Paulo   mac80211: update ...
241
242
  		*pos |= MP_F_RCODE;
  	pos++;
d19b3bf63   Rui Paulo   mac80211: replace...
243
  	memcpy(pos, target, ETH_ALEN);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
244
  	pos += ETH_ALEN;
d19b3bf63   Rui Paulo   mac80211: replace...
245
  	memcpy(pos, &target_sn, 4);
d611f062f   Rui Paulo   mac80211: update ...
246
  	pos += 4;
d19b3bf63   Rui Paulo   mac80211: replace...
247
  	memcpy(pos, &target_rcode, 2);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
248

62ae67be3   Johannes Berg   mac80211: remove ...
249
  	ieee80211_tx_skb(sdata, skb);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
250
251
  	return 0;
  }
bfc32e6a9   Javier Cardona   mac80211: Decoupl...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
  void ieee80211s_update_metric(struct ieee80211_local *local,
  		struct sta_info *stainfo, struct sk_buff *skb)
  {
  	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 */
  	stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed);
  	if (stainfo->fail_avg > 95)
  		mesh_plink_broken(stainfo);
  }
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  static u32 airtime_link_metric_get(struct ieee80211_local *local,
  				   struct sta_info *sta)
  {
  	struct ieee80211_supported_band *sband;
  	/* 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;
  
  	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  
  	if (sta->fail_avg >= 100)
  		return MAX_METRIC;
e6a9854b0   Johannes Berg   mac80211/drivers:...
285
286
287
  
  	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
  		return MAX_METRIC;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
288
289
290
291
292
  	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.
  	 */
e6a9854b0   Johannes Berg   mac80211/drivers:...
293
  	rate = sband->bitrates[sta->last_tx_rate.idx].bitrate;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
294
295
296
297
298
299
300
301
302
  	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
   *
f698d856f   Jasper Bryant-Greene   replace net_devic...
303
   * @sdata: local mesh subif
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
304
305
306
307
   * @mgmt: mesh management frame
   * @hwmp_ie: hwmp information element (PREP or PREQ)
   *
   * This function updates the path routing information to the originator and the
f99288d17   Andrey Yurovsky   mac80211: trivial...
308
   * transmitter of a HWMP PREQ or PREP frame.
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
309
310
311
312
313
314
315
   *
   * 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.
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
316
  static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
317
  			    struct ieee80211_mgmt *mgmt,
dbb81c428   Rui Paulo   mac80211: allow p...
318
  			    u8 *hwmp_ie, enum mpath_frame_type action)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
319
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
320
  	struct ieee80211_local *local = sdata->local;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
321
322
323
324
  	struct mesh_path *mpath;
  	struct sta_info *sta;
  	bool fresh_info;
  	u8 *orig_addr, *ta;
d19b3bf63   Rui Paulo   mac80211: replace...
325
  	u32 orig_sn, orig_metric;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
326
327
328
  	unsigned long orig_lifetime, exp_time;
  	u32 last_hop_metric, new_metric;
  	bool process = true;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
329
330
  
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
331
  	sta = sta_info_get(sdata, mgmt->sa);
dc0b0f7d1   Johannes Berg   mac80211: mesh hw...
332
333
  	if (!sta) {
  		rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
334
  		return 0;
dc0b0f7d1   Johannes Berg   mac80211: mesh hw...
335
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
336
337
338
339
340
341
342
343
  
  	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);
d19b3bf63   Rui Paulo   mac80211: replace...
344
  		orig_sn = PREQ_IE_ORIG_SN(hwmp_ie);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
345
346
347
348
349
350
351
352
353
354
355
356
  		orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
  		orig_metric = PREQ_IE_METRIC(hwmp_ie);
  		break;
  	case MPATH_PREP:
  		/* Originator here refers to the MP that was the destination in
  		 * the Path Request. The draft refers to that MP as the
  		 * destination address, even though usually it is the origin of
  		 * the PREP frame. We divert from the nomenclature in the draft
  		 * so that we can easily use a single function to gather path
  		 * information from both PREQ and PREP frames.
  		 */
  		orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie);
d19b3bf63   Rui Paulo   mac80211: replace...
357
  		orig_sn = PREP_IE_ORIG_SN(hwmp_ie);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
358
359
360
361
  		orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
  		orig_metric = PREP_IE_METRIC(hwmp_ie);
  		break;
  	default:
dc0b0f7d1   Johannes Berg   mac80211: mesh hw...
362
  		rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
363
364
365
366
367
368
  		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);
47846c9b0   Johannes Berg   mac80211: reduce ...
369
  	if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
370
371
372
373
374
375
  		/* 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 {
f698d856f   Jasper Bryant-Greene   replace net_devic...
376
  		mpath = mesh_path_lookup(orig_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
377
378
379
380
381
  		if (mpath) {
  			spin_lock_bh(&mpath->state_lock);
  			if (mpath->flags & MESH_PATH_FIXED)
  				fresh_info = false;
  			else if ((mpath->flags & MESH_PATH_ACTIVE) &&
d19b3bf63   Rui Paulo   mac80211: replace...
382
383
384
  			    (mpath->flags & MESH_PATH_SN_VALID)) {
  				if (SN_GT(mpath->sn, orig_sn) ||
  				    (mpath->sn == orig_sn &&
533866b12   Porsch, Marco   mac80211: fix PRE...
385
  				     new_metric >= mpath->metric)) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
386
387
388
389
390
  					process = false;
  					fresh_info = false;
  				}
  			}
  		} else {
f698d856f   Jasper Bryant-Greene   replace net_devic...
391
392
  			mesh_path_add(orig_addr, sdata);
  			mpath = mesh_path_lookup(orig_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
393
394
  			if (!mpath) {
  				rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
395
396
397
398
399
400
401
  				return 0;
  			}
  			spin_lock_bh(&mpath->state_lock);
  		}
  
  		if (fresh_info) {
  			mesh_path_assign_nexthop(mpath, sta);
d19b3bf63   Rui Paulo   mac80211: replace...
402
  			mpath->flags |= MESH_PATH_SN_VALID;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
403
  			mpath->metric = new_metric;
d19b3bf63   Rui Paulo   mac80211: replace...
404
  			mpath->sn = orig_sn;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  			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;
  	if (memcmp(orig_addr, ta, ETH_ALEN) == 0)
  		fresh_info = false;
  	else {
  		fresh_info = true;
f698d856f   Jasper Bryant-Greene   replace net_devic...
423
  		mpath = mesh_path_lookup(ta, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
424
425
426
427
428
429
430
  		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 {
f698d856f   Jasper Bryant-Greene   replace net_devic...
431
432
  			mesh_path_add(ta, sdata);
  			mpath = mesh_path_lookup(ta, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
433
434
  			if (!mpath) {
  				rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
435
436
437
438
439
440
441
  				return 0;
  			}
  			spin_lock_bh(&mpath->state_lock);
  		}
  
  		if (fresh_info) {
  			mesh_path_assign_nexthop(mpath, sta);
d19b3bf63   Rui Paulo   mac80211: replace...
442
  			mpath->flags &= ~MESH_PATH_SN_VALID;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
443
444
445
446
447
448
449
450
451
  			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);
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
452
453
454
455
  	rcu_read_unlock();
  
  	return process ? new_metric : 0;
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
456
  static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
457
  				    struct ieee80211_mgmt *mgmt,
57ef5ddb4   David Woo   mac80211: Mark a ...
458
459
  				    u8 *preq_elem, u32 metric)
  {
472dbc45d   Johannes Berg   mac80211: split o...
460
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
461
  	struct mesh_path *mpath;
d19b3bf63   Rui Paulo   mac80211: replace...
462
463
464
  	u8 *target_addr, *orig_addr;
  	u8 target_flags, ttl;
  	u32 orig_sn, target_sn, lifetime;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
465
466
  	bool reply = false;
  	bool forward = true;
d19b3bf63   Rui Paulo   mac80211: replace...
467
468
  	/* Update target SN, if present */
  	target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
469
  	orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
d19b3bf63   Rui Paulo   mac80211: replace...
470
471
472
  	target_sn = PREQ_IE_TARGET_SN(preq_elem);
  	orig_sn = PREQ_IE_ORIG_SN(preq_elem);
  	target_flags = PREQ_IE_TARGET_F(preq_elem);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
473

f3c0d88a7   Rui Paulo   mac80211: improve...
474
475
  	mhwmp_dbg("received PREQ from %pM
  ", orig_addr);
27db2e423   Rui Paulo   mac80211: add MAC...
476

47846c9b0   Johannes Berg   mac80211: reduce ...
477
  	if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
dbb81c428   Rui Paulo   mac80211: allow p...
478
479
  		mhwmp_dbg("PREQ is for us
  ");
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
480
481
482
  		forward = false;
  		reply = true;
  		metric = 0;
d19b3bf63   Rui Paulo   mac80211: replace...
483
  		if (time_after(jiffies, ifmsh->last_sn_update +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
484
  					net_traversal_jiffies(sdata)) ||
d19b3bf63   Rui Paulo   mac80211: replace...
485
486
487
  		    time_before(jiffies, ifmsh->last_sn_update)) {
  			target_sn = ++ifmsh->sn;
  			ifmsh->last_sn_update = jiffies;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
488
489
490
  		}
  	} else {
  		rcu_read_lock();
d19b3bf63   Rui Paulo   mac80211: replace...
491
  		mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
492
  		if (mpath) {
d19b3bf63   Rui Paulo   mac80211: replace...
493
494
495
496
497
  			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)) &&
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
498
499
500
  					(mpath->flags & MESH_PATH_ACTIVE)) {
  				reply = true;
  				metric = mpath->metric;
d19b3bf63   Rui Paulo   mac80211: replace...
501
502
503
  				target_sn = mpath->sn;
  				if (target_flags & MP_F_RF)
  					target_flags |= MP_F_DO;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
504
505
506
507
508
509
510
511
512
  				else
  					forward = false;
  			}
  		}
  		rcu_read_unlock();
  	}
  
  	if (reply) {
  		lifetime = PREQ_IE_LIFETIME(preq_elem);
45904f216   Javier Cardona   nl80211/mac80211:...
513
  		ttl = ifmsh->mshcfg.element_ttl;
27db2e423   Rui Paulo   mac80211: add MAC...
514
515
516
  		if (ttl != 0) {
  			mhwmp_dbg("replying to the PREQ
  ");
d19b3bf63   Rui Paulo   mac80211: replace...
517
518
519
  			mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr,
  				cpu_to_le32(target_sn), 0, orig_addr,
  				cpu_to_le32(orig_sn), mgmt->sa, 0, ttl,
aa2b59284   Luis Carlos Cobo   mac80211: clean u...
520
  				cpu_to_le32(lifetime), cpu_to_le32(metric),
f698d856f   Jasper Bryant-Greene   replace net_devic...
521
  				0, sdata);
27db2e423   Rui Paulo   mac80211: add MAC...
522
  		} else
472dbc45d   Johannes Berg   mac80211: split o...
523
  			ifmsh->mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
524
525
526
527
528
529
530
531
532
  	}
  
  	if (forward) {
  		u32 preq_id;
  		u8 hopcount, flags;
  
  		ttl = PREQ_IE_TTL(preq_elem);
  		lifetime = PREQ_IE_LIFETIME(preq_elem);
  		if (ttl <= 1) {
472dbc45d   Johannes Berg   mac80211: split o...
533
  			ifmsh->mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
534
535
  			return;
  		}
f3c0d88a7   Rui Paulo   mac80211: improve...
536
537
  		mhwmp_dbg("forwarding the PREQ from %pM
  ", orig_addr);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
538
539
540
541
542
  		--ttl;
  		flags = PREQ_IE_FLAGS(preq_elem);
  		preq_id = PREQ_IE_PREQ_ID(preq_elem);
  		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
  		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
d19b3bf63   Rui Paulo   mac80211: replace...
543
  				cpu_to_le32(orig_sn), target_flags, target_addr,
15ff63653   Johannes Berg   mac80211: use fix...
544
  				cpu_to_le32(target_sn), broadcast_addr,
aa2b59284   Luis Carlos Cobo   mac80211: clean u...
545
546
  				hopcount, ttl, cpu_to_le32(lifetime),
  				cpu_to_le32(metric), cpu_to_le32(preq_id),
f698d856f   Jasper Bryant-Greene   replace net_devic...
547
  				sdata);
c8a61a7d3   Daniel Walker   mac80211: New sta...
548
  		ifmsh->mshstats.fwded_mcast++;
472dbc45d   Johannes Berg   mac80211: split o...
549
  		ifmsh->mshstats.fwded_frames++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
550
551
  	}
  }
40b275b69   Johannes Berg   mac80211: sparse ...
552
553
554
555
556
557
  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));
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
558
  static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
559
560
561
  				    struct ieee80211_mgmt *mgmt,
  				    u8 *prep_elem, u32 metric)
  {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
562
  	struct mesh_path *mpath;
d19b3bf63   Rui Paulo   mac80211: replace...
563
  	u8 *target_addr, *orig_addr;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
564
565
  	u8 ttl, hopcount, flags;
  	u8 next_hop[ETH_ALEN];
d19b3bf63   Rui Paulo   mac80211: replace...
566
  	u32 target_sn, orig_sn, lifetime;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
567

f3c0d88a7   Rui Paulo   mac80211: improve...
568
569
  	mhwmp_dbg("received PREP from %pM
  ", PREP_IE_ORIG_ADDR(prep_elem));
dbb81c428   Rui Paulo   mac80211: allow p...
570

050ac52cb   Luis Carlos Cobo   mac80211: code fo...
571
572
573
574
575
576
  	/* Note that we divert from the draft nomenclature and denominate
  	 * destination to what the draft refers to as origininator. So in this
  	 * function destnation refers to the final destination of the PREP,
  	 * which corresponds with the originator of the PREQ which this PREP
  	 * replies
  	 */
d19b3bf63   Rui Paulo   mac80211: replace...
577
  	target_addr = PREP_IE_TARGET_ADDR(prep_elem);
47846c9b0   Johannes Berg   mac80211: reduce ...
578
  	if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
579
580
581
582
583
  		/* destination, no forwarding required */
  		return;
  
  	ttl = PREP_IE_TTL(prep_elem);
  	if (ttl <= 1) {
472dbc45d   Johannes Berg   mac80211: split o...
584
  		sdata->u.mesh.mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
585
586
587
588
  		return;
  	}
  
  	rcu_read_lock();
d19b3bf63   Rui Paulo   mac80211: replace...
589
  	mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
590
591
592
593
594
595
596
597
  	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;
  	}
40b275b69   Johannes Berg   mac80211: sparse ...
598
  	memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
599
600
601
602
603
604
  	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;
  	orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
d19b3bf63   Rui Paulo   mac80211: replace...
605
606
  	target_sn = PREP_IE_TARGET_SN(prep_elem);
  	orig_sn = PREP_IE_ORIG_SN(prep_elem);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
607
608
  
  	mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
d19b3bf63   Rui Paulo   mac80211: replace...
609
  		cpu_to_le32(orig_sn), 0, target_addr,
533866b12   Porsch, Marco   mac80211: fix PRE...
610
  		cpu_to_le32(target_sn), next_hop, hopcount,
d19b3bf63   Rui Paulo   mac80211: replace...
611
  		ttl, cpu_to_le32(lifetime), cpu_to_le32(metric),
f698d856f   Jasper Bryant-Greene   replace net_devic...
612
  		0, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
613
  	rcu_read_unlock();
c8a61a7d3   Daniel Walker   mac80211: New sta...
614
615
  
  	sdata->u.mesh.mshstats.fwded_unicast++;
472dbc45d   Johannes Berg   mac80211: split o...
616
  	sdata->u.mesh.mshstats.fwded_frames++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
617
618
619
620
  	return;
  
  fail:
  	rcu_read_unlock();
472dbc45d   Johannes Berg   mac80211: split o...
621
  	sdata->u.mesh.mshstats.dropped_frames_no_route++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
622
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
623
  static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
624
625
  			     struct ieee80211_mgmt *mgmt, u8 *perr_elem)
  {
d611f062f   Rui Paulo   mac80211: update ...
626
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
627
  	struct mesh_path *mpath;
d611f062f   Rui Paulo   mac80211: update ...
628
  	u8 ttl;
d19b3bf63   Rui Paulo   mac80211: replace...
629
  	u8 *ta, *target_addr;
d19b3bf63   Rui Paulo   mac80211: replace...
630
631
  	u32 target_sn;
  	u16 target_rcode;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
632
633
  
  	ta = mgmt->sa;
d611f062f   Rui Paulo   mac80211: update ...
634
635
636
637
638
639
  	ttl = PERR_IE_TTL(perr_elem);
  	if (ttl <= 1) {
  		ifmsh->mshstats.dropped_frames_ttl++;
  		return;
  	}
  	ttl--;
d19b3bf63   Rui Paulo   mac80211: replace...
640
641
642
  	target_addr = PERR_IE_TARGET_ADDR(perr_elem);
  	target_sn = PERR_IE_TARGET_SN(perr_elem);
  	target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
d611f062f   Rui Paulo   mac80211: update ...
643

050ac52cb   Luis Carlos Cobo   mac80211: code fo...
644
  	rcu_read_lock();
d19b3bf63   Rui Paulo   mac80211: replace...
645
  	mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
646
647
648
  	if (mpath) {
  		spin_lock_bh(&mpath->state_lock);
  		if (mpath->flags & MESH_PATH_ACTIVE &&
40b275b69   Johannes Berg   mac80211: sparse ...
649
650
  		    memcmp(ta, next_hop_deref_protected(mpath)->sta.addr,
  							ETH_ALEN) == 0 &&
d19b3bf63   Rui Paulo   mac80211: replace...
651
652
  		    (!(mpath->flags & MESH_PATH_SN_VALID) ||
  		    SN_GT(target_sn, mpath->sn))) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
653
  			mpath->flags &= ~MESH_PATH_ACTIVE;
d19b3bf63   Rui Paulo   mac80211: replace...
654
  			mpath->sn = target_sn;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
655
  			spin_unlock_bh(&mpath->state_lock);
d19b3bf63   Rui Paulo   mac80211: replace...
656
657
  			mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
  					   cpu_to_le16(target_rcode),
15ff63653   Johannes Berg   mac80211: use fix...
658
  					   broadcast_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
659
660
661
662
663
  		} else
  			spin_unlock_bh(&mpath->state_lock);
  	}
  	rcu_read_unlock();
  }
90a5e1699   Rui Paulo   mac80211: impleme...
664
665
666
667
668
669
  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;
  	struct mesh_path *mpath;
90a5e1699   Rui Paulo   mac80211: impleme...
670
671
  	u8 ttl, flags, hopcount;
  	u8 *orig_addr;
d19b3bf63   Rui Paulo   mac80211: replace...
672
  	u32 orig_sn, metric;
90a5e1699   Rui Paulo   mac80211: impleme...
673

90a5e1699   Rui Paulo   mac80211: impleme...
674
675
676
677
678
679
680
681
  	ttl = rann->rann_ttl;
  	if (ttl <= 1) {
  		ifmsh->mshstats.dropped_frames_ttl++;
  		return;
  	}
  	ttl--;
  	flags = rann->rann_flags;
  	orig_addr = rann->rann_addr;
d19b3bf63   Rui Paulo   mac80211: replace...
682
  	orig_sn = rann->rann_seq;
90a5e1699   Rui Paulo   mac80211: impleme...
683
  	hopcount = rann->rann_hopcount;
a6a58b4f1   Rui Paulo   mac80211: properl...
684
  	hopcount++;
90a5e1699   Rui Paulo   mac80211: impleme...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  	metric = rann->rann_metric;
  	mhwmp_dbg("received RANN from %pM
  ", orig_addr);
  
  	rcu_read_lock();
  	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;
  		}
  		mesh_queue_preq(mpath,
  				PREQ_Q_F_START | PREQ_Q_F_REFRESH);
  	}
d19b3bf63   Rui Paulo   mac80211: replace...
702
  	if (mpath->sn < orig_sn) {
90a5e1699   Rui Paulo   mac80211: impleme...
703
  		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
d19b3bf63   Rui Paulo   mac80211: replace...
704
  				       cpu_to_le32(orig_sn),
15ff63653   Johannes Berg   mac80211: use fix...
705
  				       0, NULL, 0, broadcast_addr,
a6a58b4f1   Rui Paulo   mac80211: properl...
706
707
  				       hopcount, ttl, 0,
  				       cpu_to_le32(metric + mpath->metric),
90a5e1699   Rui Paulo   mac80211: impleme...
708
  				       0, sdata);
d19b3bf63   Rui Paulo   mac80211: replace...
709
  		mpath->sn = orig_sn;
90a5e1699   Rui Paulo   mac80211: impleme...
710
711
712
  	}
  	rcu_read_unlock();
  }
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
713

f698d856f   Jasper Bryant-Greene   replace net_devic...
714
  void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
715
716
717
718
719
720
  			    struct ieee80211_mgmt *mgmt,
  			    size_t len)
  {
  	struct ieee802_11_elems elems;
  	size_t baselen;
  	u32 last_hop_metric;
9c80d3dc2   Johannes Berg   mac80211: fix act...
721
722
723
  	/* need action_code */
  	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
  		return;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
724
725
726
  	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);
dbb81c428   Rui Paulo   mac80211: allow p...
727
728
  	if (elems.preq) {
  		if (elems.preq_len != 37)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
729
730
  			/* Right now we support just 1 destination and no AE */
  			return;
dbb81c428   Rui Paulo   mac80211: allow p...
731
732
733
734
735
736
737
738
  		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)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
739
740
  			/* Right now we support no AE */
  			return;
dbb81c428   Rui Paulo   mac80211: allow p...
741
742
743
744
745
746
747
  		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) {
d611f062f   Rui Paulo   mac80211: update ...
748
  		if (elems.perr_len != 15)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
749
750
  			/* Right now we support only one destination per PERR */
  			return;
f698d856f   Jasper Bryant-Greene   replace net_devic...
751
  		hwmp_perr_frame_process(sdata, mgmt, elems.perr);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
752
  	}
90a5e1699   Rui Paulo   mac80211: impleme...
753
754
  	if (elems.rann)
  		hwmp_rann_frame_process(sdata, mgmt, elems.rann);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
755
756
757
758
759
760
761
762
763
764
765
766
767
  }
  
  /**
   * 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)
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
768
  	struct ieee80211_sub_if_data *sdata = mpath->sdata;
472dbc45d   Johannes Berg   mac80211: split o...
769
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
770
  	struct mesh_preq_queue *preq_node;
59615b5f9   Andrey Yurovsky   mac80211: fix all...
771
  	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
772
  	if (!preq_node) {
27db2e423   Rui Paulo   mac80211: add MAC...
773
774
  		mhwmp_dbg("could not allocate PREQ node
  ");
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
775
776
  		return;
  	}
472dbc45d   Johannes Berg   mac80211: split o...
777
778
779
  	spin_lock(&ifmsh->mesh_preq_queue_lock);
  	if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
  		spin_unlock(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
780
781
  		kfree(preq_node);
  		if (printk_ratelimit())
27db2e423   Rui Paulo   mac80211: add MAC...
782
783
  			mhwmp_dbg("PREQ node queue full
  ");
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
784
785
786
787
788
  		return;
  	}
  
  	memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
  	preq_node->flags = flags;
472dbc45d   Johannes Berg   mac80211: split o...
789
790
791
  	list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
  	++ifmsh->preq_queue_len;
  	spin_unlock(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
792

472dbc45d   Johannes Berg   mac80211: split o...
793
  	if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
64592c8fc   Johannes Berg   mac80211: use com...
794
  		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
795

472dbc45d   Johannes Berg   mac80211: split o...
796
  	else if (time_before(jiffies, ifmsh->last_preq)) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
797
798
799
  		/* avoid long wait if did not send preqs for a long time
  		 * and jiffies wrapped around
  		 */
472dbc45d   Johannes Berg   mac80211: split o...
800
  		ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
64592c8fc   Johannes Berg   mac80211: use com...
801
  		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
802
  	} else
472dbc45d   Johannes Berg   mac80211: split o...
803
  		mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
804
805
806
807
808
809
  						min_preq_int_jiff(sdata));
  }
  
  /**
   * mesh_path_start_discovery - launch a path discovery from the PREQ queue
   *
f698d856f   Jasper Bryant-Greene   replace net_devic...
810
   * @sdata: local mesh subif
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
811
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
812
  void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
813
  {
472dbc45d   Johannes Berg   mac80211: split o...
814
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
815
816
  	struct mesh_preq_queue *preq_node;
  	struct mesh_path *mpath;
d19b3bf63   Rui Paulo   mac80211: replace...
817
  	u8 ttl, target_flags;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
818
  	u32 lifetime;
a43816df2   Johannes Berg   mac80211: mesh: f...
819
  	spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
472dbc45d   Johannes Berg   mac80211: split o...
820
821
  	if (!ifmsh->preq_queue_len ||
  		time_before(jiffies, ifmsh->last_preq +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
822
  				min_preq_int_jiff(sdata))) {
a43816df2   Johannes Berg   mac80211: mesh: f...
823
  		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
824
825
  		return;
  	}
472dbc45d   Johannes Berg   mac80211: split o...
826
  	preq_node = list_first_entry(&ifmsh->preq_queue.list,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
827
828
  			struct mesh_preq_queue, list);
  	list_del(&preq_node->list);
472dbc45d   Johannes Berg   mac80211: split o...
829
  	--ifmsh->preq_queue_len;
a43816df2   Johannes Berg   mac80211: mesh: f...
830
  	spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
831
832
  
  	rcu_read_lock();
f698d856f   Jasper Bryant-Greene   replace net_devic...
833
  	mpath = mesh_path_lookup(preq_node->dst, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
  	if (!mpath)
  		goto enddiscovery;
  
  	spin_lock_bh(&mpath->state_lock);
  	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;
  	}
472dbc45d   Johannes Berg   mac80211: split o...
854
  	ifmsh->last_preq = jiffies;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
855

d19b3bf63   Rui Paulo   mac80211: replace...
856
  	if (time_after(jiffies, ifmsh->last_sn_update +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
857
  				net_traversal_jiffies(sdata)) ||
d19b3bf63   Rui Paulo   mac80211: replace...
858
859
860
  	    time_before(jiffies, ifmsh->last_sn_update)) {
  		++ifmsh->sn;
  		sdata->u.mesh.last_sn_update = jiffies;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
861
862
  	}
  	lifetime = default_lifetime(sdata);
45904f216   Javier Cardona   nl80211/mac80211:...
863
  	ttl = sdata->u.mesh.mshcfg.element_ttl;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
864
  	if (ttl == 0) {
472dbc45d   Johannes Berg   mac80211: split o...
865
  		sdata->u.mesh.mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
866
867
868
869
870
  		spin_unlock_bh(&mpath->state_lock);
  		goto enddiscovery;
  	}
  
  	if (preq_node->flags & PREQ_Q_F_REFRESH)
d19b3bf63   Rui Paulo   mac80211: replace...
871
  		target_flags = MP_F_DO;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
872
  	else
d19b3bf63   Rui Paulo   mac80211: replace...
873
  		target_flags = MP_F_RF;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
874
875
  
  	spin_unlock_bh(&mpath->state_lock);
47846c9b0   Johannes Berg   mac80211: reduce ...
876
  	mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
d19b3bf63   Rui Paulo   mac80211: replace...
877
  			cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
15ff63653   Johannes Berg   mac80211: use fix...
878
  			cpu_to_le32(mpath->sn), broadcast_addr, 0,
aa2b59284   Luis Carlos Cobo   mac80211: clean u...
879
  			ttl, cpu_to_le32(lifetime), 0,
472dbc45d   Johannes Berg   mac80211: split o...
880
  			cpu_to_le32(ifmsh->preq_id++), sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
881
882
883
884
885
886
887
888
  	mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
  
  enddiscovery:
  	rcu_read_unlock();
  	kfree(preq_node);
  }
  
  /**
2182b830f   Rami Rosen   mac80211: trivial...
889
   * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
890
   *
e32f85f7b   Luis Carlos Cobo   mac80211: fix use...
891
   * @skb: 802.11 frame to be sent
f698d856f   Jasper Bryant-Greene   replace net_devic...
892
   * @sdata: network subif the frame will be sent through
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
893
894
895
896
897
898
   *
   * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
   * found, the function will start a path discovery and queue the frame so it is
   * sent when the path is resolved. This means the caller must not free the skb
   * in this case.
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
899
900
  int mesh_nexthop_lookup(struct sk_buff *skb,
  			struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
901
  {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
902
903
  	struct sk_buff *skb_to_free = NULL;
  	struct mesh_path *mpath;
40b275b69   Johannes Berg   mac80211: sparse ...
904
  	struct sta_info *next_hop;
e32f85f7b   Luis Carlos Cobo   mac80211: fix use...
905
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
d19b3bf63   Rui Paulo   mac80211: replace...
906
  	u8 *target_addr = hdr->addr3;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
907
908
909
  	int err = 0;
  
  	rcu_read_lock();
d19b3bf63   Rui Paulo   mac80211: replace...
910
  	mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
911
912
  
  	if (!mpath) {
d19b3bf63   Rui Paulo   mac80211: replace...
913
914
  		mesh_path_add(target_addr, sdata);
  		mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
915
  		if (!mpath) {
472dbc45d   Johannes Berg   mac80211: split o...
916
  			sdata->u.mesh.mshstats.dropped_frames_no_route++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
917
918
919
920
921
922
  			err = -ENOSPC;
  			goto endlookup;
  		}
  	}
  
  	if (mpath->flags & MESH_PATH_ACTIVE) {
f64f9e719   Joe Perches   net: Move && and ...
923
  		if (time_after(jiffies,
7b324d28a   Javier Cardona   mac80211: Revert ...
924
  			       mpath->exp_time -
f64f9e719   Joe Perches   net: Move && and ...
925
  			       msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
47846c9b0   Johannes Berg   mac80211: reduce ...
926
  		    !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
f64f9e719   Joe Perches   net: Move && and ...
927
928
  		    !(mpath->flags & MESH_PATH_RESOLVING) &&
  		    !(mpath->flags & MESH_PATH_FIXED)) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
929
930
931
  			mesh_queue_preq(mpath,
  					PREQ_Q_F_START | PREQ_Q_F_REFRESH);
  		}
40b275b69   Johannes Berg   mac80211: sparse ...
932
933
934
935
936
  		next_hop = rcu_dereference(mpath->next_hop);
  		if (next_hop)
  			memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
  		else
  			err = -ENOENT;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
937
  	} else {
249b405cf   Javier Cardona   mac80211: Fix reg...
938
  		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
939
940
941
942
943
944
  		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
  			/* Start discovery only if it is not running yet */
  			mesh_queue_preq(mpath, PREQ_Q_F_START);
  		}
  
  		if (skb_queue_len(&mpath->frame_queue) >=
fe5834346   Javier Cardona   mac80211: Improve...
945
946
  				MESH_FRAME_QUEUE_LEN)
  			skb_to_free = skb_dequeue(&mpath->frame_queue);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
947

249b405cf   Javier Cardona   mac80211: Fix reg...
948
  		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
949
950
  		skb_queue_tail(&mpath->frame_queue, skb);
  		if (skb_to_free)
f698d856f   Jasper Bryant-Greene   replace net_devic...
951
  			mesh_path_discard_frame(skb_to_free, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
952
953
954
955
956
957
958
959
960
961
  		err = -ENOENT;
  	}
  
  endlookup:
  	rcu_read_unlock();
  	return err;
  }
  
  void mesh_path_timer(unsigned long data)
  {
dea4096bc   Johannes Berg   mac80211: remove ...
962
963
  	struct mesh_path *mpath = (void *) data;
  	struct ieee80211_sub_if_data *sdata = mpath->sdata;
5bb644a0f   Johannes Berg   mac80211: cancel/...
964

dea4096bc   Johannes Berg   mac80211: remove ...
965
  	if (sdata->local->quiescing)
5bb644a0f   Johannes Berg   mac80211: cancel/...
966
  		return;
5bb644a0f   Johannes Berg   mac80211: cancel/...
967
968
  
  	spin_lock_bh(&mpath->state_lock);
cfa22c716   Luis Carlos Cobo   mac80211: always ...
969
  	if (mpath->flags & MESH_PATH_RESOLVED ||
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
970
971
972
973
974
975
976
977
978
979
980
981
982
  			(!(mpath->flags & MESH_PATH_RESOLVING)))
  		mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
  	else if (mpath->discovery_retries < max_preq_retries(sdata)) {
  		++mpath->discovery_retries;
  		mpath->discovery_timeout *= 2;
  		mesh_queue_preq(mpath, 0);
  	} else {
  		mpath->flags = 0;
  		mpath->exp_time = jiffies;
  		mesh_path_flush_pending(mpath);
  	}
  
  	spin_unlock_bh(&mpath->state_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
983
  }
e304bfd30   Rui Paulo   mac80211: impleme...
984
985
986
987
988
  
  void
  mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
47846c9b0   Johannes Berg   mac80211: reduce ...
989
  	mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
e304bfd30   Rui Paulo   mac80211: impleme...
990
  			       cpu_to_le32(++ifmsh->sn),
15ff63653   Johannes Berg   mac80211: use fix...
991
  			       0, NULL, 0, broadcast_addr,
45904f216   Javier Cardona   nl80211/mac80211:...
992
993
  			       0, sdata->u.mesh.mshcfg.element_ttl,
  			       0, 0, 0, sdata);
e304bfd30   Rui Paulo   mac80211: impleme...
994
  }