Blame view

net/mac80211/mesh_hwmp.c 31.4 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>
2cca397f7   Javier Cardona   mac80211: Defer t...
10
  #include "wme.h"
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
11
  #include "mesh.h"
27db2e423   Rui Paulo   mac80211: add MAC...
12
  #ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
7646887a5   Javier Cardona   mac80211: improve...
13
14
15
  #define mhwmp_dbg(fmt, args...) \
  	printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "
  ", sdata->name, ##args)
27db2e423   Rui Paulo   mac80211: add MAC...
16
17
18
  #else
  #define mhwmp_dbg(fmt, args...)   do { (void)(0); } while (0)
  #endif
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
19
20
21
22
23
24
25
26
27
28
29
30
  #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 ...
31
32
33
34
  /* Unknown Sequence Number */
  #define MP_F_USN    0x01
  /* Reason code Present */
  #define MP_F_RCODE  0x02
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
35

90a5e1699   Rui Paulo   mac80211: impleme...
36
  static void mesh_queue_preq(struct mesh_path *, u8);
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
37
38
39
40
  static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
  {
  	if (ae)
  		offset += 6;
ae7245cbf   Harvey Harrison   wireless: use get...
41
  	return get_unaligned_le32(preq_elem + offset);
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
42
  }
d611f062f   Rui Paulo   mac80211: update ...
43
44
45
46
47
48
  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...
49
  /* HWMP IE processing macros */
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
50
51
52
53
54
55
56
  #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)
497888cf6   Phil Carmody   treewide: fix pot...
57
58
59
  #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))
d19b3bf63   Rui Paulo   mac80211: replace...
60
61
  #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)
497888cf6   Phil Carmody   treewide: fix pot...
62
  #define PREQ_IE_TARGET_SN(x) 	u32_field_get(x, 33, AE_F_SET(x))
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
63
64
65
66
67
  
  
  #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)
25d49e4d6   Thomas Pedersen   mac80211: update ...
68
69
  #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))
497888cf6   Phil Carmody   treewide: fix pot...
70
71
  #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))
25d49e4d6   Thomas Pedersen   mac80211: update ...
72
73
  #define PREP_IE_TARGET_ADDR(x)	(x + 3)
  #define PREP_IE_TARGET_SN(x)	u32_field_get(x, 9, 0)
a00de5d08   Luis Carlos Cobo   mac80211: path IE...
74

d611f062f   Rui Paulo   mac80211: update ...
75
  #define PERR_IE_TTL(x)		(*(x))
d19b3bf63   Rui Paulo   mac80211: replace...
76
77
  #define PERR_IE_TARGET_FLAGS(x)	(*(x + 2))
  #define PERR_IE_TARGET_ADDR(x)	(x + 3)
497888cf6   Phil Carmody   treewide: fix pot...
78
79
  #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...
80

050ac52cb   Luis Carlos Cobo   mac80211: code fo...
81
  #define MSEC_TO_TU(x) (x*1000/1024)
d19b3bf63   Rui Paulo   mac80211: replace...
82
83
  #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...
84
85
  
  #define net_traversal_jiffies(s) \
472dbc45d   Johannes Berg   mac80211: split o...
86
  	msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
87
  #define default_lifetime(s) \
472dbc45d   Johannes Berg   mac80211: split o...
88
  	MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
89
  #define min_preq_int_jiff(s) \
472dbc45d   Johannes Berg   mac80211: split o...
90
91
  	(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...
92
  #define disc_timeout_jiff(s) \
472dbc45d   Johannes Berg   mac80211: split o...
93
  	msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
94
95
96
97
  
  enum mpath_frame_type {
  	MPATH_PREQ = 0,
  	MPATH_PREP,
90a5e1699   Rui Paulo   mac80211: impleme...
98
99
  	MPATH_PERR,
  	MPATH_RANN
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
100
  };
15ff63653   Johannes Berg   mac80211: use fix...
101
  static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
102
  static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
d19b3bf63   Rui Paulo   mac80211: replace...
103
  		u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
15ff63653   Johannes Berg   mac80211: use fix...
104
105
  		__le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
  		__le32 lifetime, __le32 metric, __le32 preq_id,
d19b3bf63   Rui Paulo   mac80211: replace...
106
  		struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
107
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
108
  	struct ieee80211_local *local = sdata->local;
3b69a9c5f   Thomas Pedersen   mac80211: comment...
109
  	struct sk_buff *skb;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
110
  	struct ieee80211_mgmt *mgmt;
3b69a9c5f   Thomas Pedersen   mac80211: comment...
111
112
113
  	u8 *pos, ie_len;
  	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
  		      sizeof(mgmt->u.action.u.mesh_action);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
114

3b69a9c5f   Thomas Pedersen   mac80211: comment...
115
116
117
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
  			    hdr_len +
  			    2 + 37); /* max HWMP IE */
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
118
119
120
  	if (!skb)
  		return -1;
  	skb_reserve(skb, local->hw.extra_tx_headroom);
3b69a9c5f   Thomas Pedersen   mac80211: comment...
121
122
  	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
  	memset(mgmt, 0, hdr_len);
e7827a703   Harvey Harrison   mac80211: remove ...
123
124
  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					  IEEE80211_STYPE_ACTION);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
125
126
  
  	memcpy(mgmt->da, da, ETH_ALEN);
47846c9b0   Johannes Berg   mac80211: reduce ...
127
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
90a5e1699   Rui Paulo   mac80211: impleme...
128
  	/* BSSID == SA */
47846c9b0   Johannes Berg   mac80211: reduce ...
129
  	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
25d49e4d6   Thomas Pedersen   mac80211: update ...
130
131
132
  	mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
  	mgmt->u.action.u.mesh_action.action_code =
  					WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
133
134
135
  
  	switch (action) {
  	case MPATH_PREQ:
7646887a5   Javier Cardona   mac80211: improve...
136
  		mhwmp_dbg("sending PREQ to %pM", target);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
137
138
139
140
141
  		ie_len = 37;
  		pos = skb_put(skb, 2 + ie_len);
  		*pos++ = WLAN_EID_PREQ;
  		break;
  	case MPATH_PREP:
7646887a5   Javier Cardona   mac80211: improve...
142
  		mhwmp_dbg("sending PREP to %pM", target);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
143
144
145
146
  		ie_len = 31;
  		pos = skb_put(skb, 2 + ie_len);
  		*pos++ = WLAN_EID_PREP;
  		break;
90a5e1699   Rui Paulo   mac80211: impleme...
147
  	case MPATH_RANN:
7646887a5   Javier Cardona   mac80211: improve...
148
  		mhwmp_dbg("sending RANN from %pM", orig_addr);
90a5e1699   Rui Paulo   mac80211: impleme...
149
150
151
152
  		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...
153
  	default:
812714d74   Patrick McHardy   mac80211: mesh hw...
154
  		kfree_skb(skb);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
155
156
157
158
159
160
161
  		return -ENOTSUPP;
  		break;
  	}
  	*pos++ = ie_len;
  	*pos++ = flags;
  	*pos++ = hop_count;
  	*pos++ = ttl;
25d49e4d6   Thomas Pedersen   mac80211: update ...
162
163
164
165
  	if (action == MPATH_PREP) {
  		memcpy(pos, target, ETH_ALEN);
  		pos += ETH_ALEN;
  		memcpy(pos, &target_sn, 4);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
166
  		pos += 4;
25d49e4d6   Thomas Pedersen   mac80211: update ...
167
168
169
170
171
172
173
174
  	} 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);
90a5e1699   Rui Paulo   mac80211: impleme...
175
176
  		pos += 4;
  	}
25d49e4d6   Thomas Pedersen   mac80211: update ...
177
178
  	memcpy(pos, &lifetime, 4);	/* interval for RANN */
  	pos += 4;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
179
180
181
  	memcpy(pos, &metric, 4);
  	pos += 4;
  	if (action == MPATH_PREQ) {
25d49e4d6   Thomas Pedersen   mac80211: update ...
182
  		*pos++ = 1; /* destination count */
d19b3bf63   Rui Paulo   mac80211: replace...
183
  		*pos++ = target_flags;
d19b3bf63   Rui Paulo   mac80211: replace...
184
  		memcpy(pos, target, ETH_ALEN);
90a5e1699   Rui Paulo   mac80211: impleme...
185
  		pos += ETH_ALEN;
d19b3bf63   Rui Paulo   mac80211: replace...
186
  		memcpy(pos, &target_sn, 4);
25d49e4d6   Thomas Pedersen   mac80211: update ...
187
188
189
190
191
192
  		pos += 4;
  	} else if (action == MPATH_PREP) {
  		memcpy(pos, orig_addr, ETH_ALEN);
  		pos += ETH_ALEN;
  		memcpy(pos, &orig_sn, 4);
  		pos += 4;
90a5e1699   Rui Paulo   mac80211: impleme...
193
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
194

62ae67be3   Johannes Berg   mac80211: remove ...
195
  	ieee80211_tx_skb(sdata, skb);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
196
197
  	return 0;
  }
2cca397f7   Javier Cardona   mac80211: Defer t...
198
199
200
201
202
203
  
  /*  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)
  {
2cca397f7   Javier Cardona   mac80211: Defer t...
204
205
206
207
208
209
210
211
212
213
214
  	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;
2154c81c3   Javier Cardona   mac80211: Mesh da...
215
  	ieee80211_set_qos_hdr(sdata, skb);
2cca397f7   Javier Cardona   mac80211: Defer t...
216
  }
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
217
218
219
  /**
   * mesh_send_path error - Sends a PERR mesh management frame
   *
d19b3bf63   Rui Paulo   mac80211: replace...
220
221
222
   * @target: broken destination
   * @target_sn: SN of the broken destination
   * @target_rcode: reason code for this PERR
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
223
   * @ra: node this frame is addressed to
2cca397f7   Javier Cardona   mac80211: Defer t...
224
225
226
227
   *
   * 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.
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
228
   */
d19b3bf63   Rui Paulo   mac80211: replace...
229
  int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
15ff63653   Johannes Berg   mac80211: use fix...
230
231
  		       __le16 target_rcode, const u8 *ra,
  		       struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
232
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
233
  	struct ieee80211_local *local = sdata->local;
3b69a9c5f   Thomas Pedersen   mac80211: comment...
234
  	struct sk_buff *skb;
dca7e9430   Thomas Pedersen   {nl,cfg,mac}80211...
235
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
236
  	struct ieee80211_mgmt *mgmt;
3b69a9c5f   Thomas Pedersen   mac80211: comment...
237
238
239
  	u8 *pos, ie_len;
  	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
  		      sizeof(mgmt->u.action.u.mesh_action);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
240

dca7e9430   Thomas Pedersen   {nl,cfg,mac}80211...
241
242
  	if (time_before(jiffies, ifmsh->next_perr))
  		return -EAGAIN;
3b69a9c5f   Thomas Pedersen   mac80211: comment...
243
244
245
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
  			    hdr_len +
  			    2 + 15 /* PERR IE */);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
246
247
  	if (!skb)
  		return -1;
2cca397f7   Javier Cardona   mac80211: Defer t...
248
  	skb_reserve(skb, local->tx_headroom + local->hw.extra_tx_headroom);
3b69a9c5f   Thomas Pedersen   mac80211: comment...
249
250
  	mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
  	memset(mgmt, 0, hdr_len);
e7827a703   Harvey Harrison   mac80211: remove ...
251
252
  	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  					  IEEE80211_STYPE_ACTION);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
253
254
  
  	memcpy(mgmt->da, ra, ETH_ALEN);
47846c9b0   Johannes Berg   mac80211: reduce ...
255
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
25d49e4d6   Thomas Pedersen   mac80211: update ...
256
257
258
259
260
  	/* 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;
d611f062f   Rui Paulo   mac80211: update ...
261
  	ie_len = 15;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
262
263
264
  	pos = skb_put(skb, 2 + ie_len);
  	*pos++ = WLAN_EID_PERR;
  	*pos++ = ie_len;
d611f062f   Rui Paulo   mac80211: update ...
265
  	/* ttl */
45904f216   Javier Cardona   nl80211/mac80211:...
266
  	*pos++ = ttl;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
267
268
  	/* number of destinations */
  	*pos++ = 1;
d611f062f   Rui Paulo   mac80211: update ...
269
270
271
272
273
  	/*
  	 * 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...
274
  	if (!target_sn)
d611f062f   Rui Paulo   mac80211: update ...
275
  		*pos |= MP_F_USN;
d19b3bf63   Rui Paulo   mac80211: replace...
276
  	if (target_rcode)
d611f062f   Rui Paulo   mac80211: update ...
277
278
  		*pos |= MP_F_RCODE;
  	pos++;
d19b3bf63   Rui Paulo   mac80211: replace...
279
  	memcpy(pos, target, ETH_ALEN);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
280
  	pos += ETH_ALEN;
d19b3bf63   Rui Paulo   mac80211: replace...
281
  	memcpy(pos, &target_sn, 4);
d611f062f   Rui Paulo   mac80211: update ...
282
  	pos += 4;
d19b3bf63   Rui Paulo   mac80211: replace...
283
  	memcpy(pos, &target_rcode, 2);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
284

2cca397f7   Javier Cardona   mac80211: Defer t...
285
286
  	/* see note in function header */
  	prepare_frame_for_deferred_tx(sdata, skb);
dca7e9430   Thomas Pedersen   {nl,cfg,mac}80211...
287
288
  	ifmsh->next_perr = TU_TO_EXP_TIME(
  				   ifmsh->mshcfg.dot11MeshHWMPperrMinInterval);
2cca397f7   Javier Cardona   mac80211: Defer t...
289
  	ieee80211_add_pending_skb(local, skb);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
290
291
  	return 0;
  }
bfc32e6a9   Javier Cardona   mac80211: Decoupl...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  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...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  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:...
325
326
327
  
  	if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
  		return MAX_METRIC;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
328
329
330
331
332
  	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:...
333
  	rate = sband->bitrates[sta->last_tx_rate.idx].bitrate;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
334
335
336
337
338
339
340
341
342
  	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...
343
   * @sdata: local mesh subif
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
344
345
346
347
   * @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...
348
   * transmitter of a HWMP PREQ or PREP frame.
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
349
350
351
352
353
354
355
   *
   * 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...
356
  static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
357
  			    struct ieee80211_mgmt *mgmt,
dbb81c428   Rui Paulo   mac80211: allow p...
358
  			    u8 *hwmp_ie, enum mpath_frame_type action)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
359
  {
f698d856f   Jasper Bryant-Greene   replace net_devic...
360
  	struct ieee80211_local *local = sdata->local;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
361
362
363
364
  	struct mesh_path *mpath;
  	struct sta_info *sta;
  	bool fresh_info;
  	u8 *orig_addr, *ta;
d19b3bf63   Rui Paulo   mac80211: replace...
365
  	u32 orig_sn, orig_metric;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
366
367
368
  	unsigned long orig_lifetime, exp_time;
  	u32 last_hop_metric, new_metric;
  	bool process = true;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
369
370
  
  	rcu_read_lock();
abe60632f   Johannes Berg   mac80211: make st...
371
  	sta = sta_info_get(sdata, mgmt->sa);
dc0b0f7d1   Johannes Berg   mac80211: mesh hw...
372
373
  	if (!sta) {
  		rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
374
  		return 0;
dc0b0f7d1   Johannes Berg   mac80211: mesh hw...
375
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
376
377
378
379
380
381
382
383
  
  	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...
384
  		orig_sn = PREQ_IE_ORIG_SN(hwmp_ie);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
385
386
387
388
  		orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
  		orig_metric = PREQ_IE_METRIC(hwmp_ie);
  		break;
  	case MPATH_PREP:
3c26f1f68   Thomas Pedersen   mac80211: fix swi...
389
390
  		/* Originator here refers to the MP that was the target in the
  		 * Path Request. We divert from the nomenclature in the draft
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
391
392
393
  		 * so that we can easily use a single function to gather path
  		 * information from both PREQ and PREP frames.
  		 */
3c26f1f68   Thomas Pedersen   mac80211: fix swi...
394
395
  		orig_addr = PREP_IE_TARGET_ADDR(hwmp_ie);
  		orig_sn = PREP_IE_TARGET_SN(hwmp_ie);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
396
397
398
399
  		orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
  		orig_metric = PREP_IE_METRIC(hwmp_ie);
  		break;
  	default:
dc0b0f7d1   Johannes Berg   mac80211: mesh hw...
400
  		rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
401
402
403
404
405
406
  		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 ...
407
  	if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
408
409
410
411
412
413
  		/* 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...
414
  		mpath = mesh_path_lookup(orig_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
415
416
417
418
419
  		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...
420
421
422
  			    (mpath->flags & MESH_PATH_SN_VALID)) {
  				if (SN_GT(mpath->sn, orig_sn) ||
  				    (mpath->sn == orig_sn &&
533866b12   Porsch, Marco   mac80211: fix PRE...
423
  				     new_metric >= mpath->metric)) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
424
425
426
427
428
  					process = false;
  					fresh_info = false;
  				}
  			}
  		} else {
f698d856f   Jasper Bryant-Greene   replace net_devic...
429
430
  			mesh_path_add(orig_addr, sdata);
  			mpath = mesh_path_lookup(orig_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
431
432
  			if (!mpath) {
  				rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
433
434
435
436
437
438
439
  				return 0;
  			}
  			spin_lock_bh(&mpath->state_lock);
  		}
  
  		if (fresh_info) {
  			mesh_path_assign_nexthop(mpath, sta);
d19b3bf63   Rui Paulo   mac80211: replace...
440
  			mpath->flags |= MESH_PATH_SN_VALID;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
441
  			mpath->metric = new_metric;
d19b3bf63   Rui Paulo   mac80211: replace...
442
  			mpath->sn = orig_sn;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  			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...
461
  		mpath = mesh_path_lookup(ta, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
462
463
464
465
466
467
468
  		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...
469
470
  			mesh_path_add(ta, sdata);
  			mpath = mesh_path_lookup(ta, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
471
472
  			if (!mpath) {
  				rcu_read_unlock();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
473
474
475
476
477
478
479
  				return 0;
  			}
  			spin_lock_bh(&mpath->state_lock);
  		}
  
  		if (fresh_info) {
  			mesh_path_assign_nexthop(mpath, sta);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
480
481
482
483
484
485
486
487
488
  			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...
489
490
491
492
  	rcu_read_unlock();
  
  	return process ? new_metric : 0;
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
493
  static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
494
  				    struct ieee80211_mgmt *mgmt,
57ef5ddb4   David Woo   mac80211: Mark a ...
495
496
  				    u8 *preq_elem, u32 metric)
  {
472dbc45d   Johannes Berg   mac80211: split o...
497
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
498
  	struct mesh_path *mpath;
d19b3bf63   Rui Paulo   mac80211: replace...
499
500
501
  	u8 *target_addr, *orig_addr;
  	u8 target_flags, ttl;
  	u32 orig_sn, target_sn, lifetime;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
502
503
  	bool reply = false;
  	bool forward = true;
d19b3bf63   Rui Paulo   mac80211: replace...
504
505
  	/* Update target SN, if present */
  	target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
506
  	orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
d19b3bf63   Rui Paulo   mac80211: replace...
507
508
509
  	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...
510

7646887a5   Javier Cardona   mac80211: improve...
511
  	mhwmp_dbg("received PREQ from %pM", orig_addr);
27db2e423   Rui Paulo   mac80211: add MAC...
512

47846c9b0   Johannes Berg   mac80211: reduce ...
513
  	if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
7646887a5   Javier Cardona   mac80211: improve...
514
  		mhwmp_dbg("PREQ is for us");
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
515
516
517
  		forward = false;
  		reply = true;
  		metric = 0;
d19b3bf63   Rui Paulo   mac80211: replace...
518
  		if (time_after(jiffies, ifmsh->last_sn_update +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
519
  					net_traversal_jiffies(sdata)) ||
d19b3bf63   Rui Paulo   mac80211: replace...
520
521
522
  		    time_before(jiffies, ifmsh->last_sn_update)) {
  			target_sn = ++ifmsh->sn;
  			ifmsh->last_sn_update = jiffies;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
523
524
525
  		}
  	} else {
  		rcu_read_lock();
d19b3bf63   Rui Paulo   mac80211: replace...
526
  		mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
527
  		if (mpath) {
d19b3bf63   Rui Paulo   mac80211: replace...
528
529
530
531
532
  			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...
533
534
535
  					(mpath->flags & MESH_PATH_ACTIVE)) {
  				reply = true;
  				metric = mpath->metric;
d19b3bf63   Rui Paulo   mac80211: replace...
536
537
538
  				target_sn = mpath->sn;
  				if (target_flags & MP_F_RF)
  					target_flags |= MP_F_DO;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
539
540
541
542
543
544
545
546
547
  				else
  					forward = false;
  			}
  		}
  		rcu_read_unlock();
  	}
  
  	if (reply) {
  		lifetime = PREQ_IE_LIFETIME(preq_elem);
45904f216   Javier Cardona   nl80211/mac80211:...
548
  		ttl = ifmsh->mshcfg.element_ttl;
27db2e423   Rui Paulo   mac80211: add MAC...
549
  		if (ttl != 0) {
7646887a5   Javier Cardona   mac80211: improve...
550
  			mhwmp_dbg("replying to the PREQ");
3c26f1f68   Thomas Pedersen   mac80211: fix swi...
551
552
553
  			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,
aa2b59284   Luis Carlos Cobo   mac80211: clean u...
554
  				cpu_to_le32(lifetime), cpu_to_le32(metric),
f698d856f   Jasper Bryant-Greene   replace net_devic...
555
  				0, sdata);
27db2e423   Rui Paulo   mac80211: add MAC...
556
  		} else
472dbc45d   Johannes Berg   mac80211: split o...
557
  			ifmsh->mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
558
559
560
561
562
563
564
565
566
  	}
  
  	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...
567
  			ifmsh->mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
568
569
  			return;
  		}
7646887a5   Javier Cardona   mac80211: improve...
570
  		mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
571
572
573
574
575
  		--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...
576
  				cpu_to_le32(orig_sn), target_flags, target_addr,
15ff63653   Johannes Berg   mac80211: use fix...
577
  				cpu_to_le32(target_sn), broadcast_addr,
aa2b59284   Luis Carlos Cobo   mac80211: clean u...
578
579
  				hopcount, ttl, cpu_to_le32(lifetime),
  				cpu_to_le32(metric), cpu_to_le32(preq_id),
f698d856f   Jasper Bryant-Greene   replace net_devic...
580
  				sdata);
c8a61a7d3   Daniel Walker   mac80211: New sta...
581
  		ifmsh->mshstats.fwded_mcast++;
472dbc45d   Johannes Berg   mac80211: split o...
582
  		ifmsh->mshstats.fwded_frames++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
583
584
  	}
  }
40b275b69   Johannes Berg   mac80211: sparse ...
585
586
587
588
589
590
  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...
591
  static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
592
593
594
  				    struct ieee80211_mgmt *mgmt,
  				    u8 *prep_elem, u32 metric)
  {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
595
  	struct mesh_path *mpath;
d19b3bf63   Rui Paulo   mac80211: replace...
596
  	u8 *target_addr, *orig_addr;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
597
598
  	u8 ttl, hopcount, flags;
  	u8 next_hop[ETH_ALEN];
d19b3bf63   Rui Paulo   mac80211: replace...
599
  	u32 target_sn, orig_sn, lifetime;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
600

7646887a5   Javier Cardona   mac80211: improve...
601
  	mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
dbb81c428   Rui Paulo   mac80211: allow p...
602

3c26f1f68   Thomas Pedersen   mac80211: fix swi...
603
604
  	orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
  	if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
605
606
607
608
609
  		/* destination, no forwarding required */
  		return;
  
  	ttl = PREP_IE_TTL(prep_elem);
  	if (ttl <= 1) {
472dbc45d   Johannes Berg   mac80211: split o...
610
  		sdata->u.mesh.mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
611
612
613
614
  		return;
  	}
  
  	rcu_read_lock();
3c26f1f68   Thomas Pedersen   mac80211: fix swi...
615
  	mpath = mesh_path_lookup(orig_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
616
617
618
619
620
621
622
623
  	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 ...
624
  	memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
625
626
627
628
629
  	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;
3c26f1f68   Thomas Pedersen   mac80211: fix swi...
630
  	target_addr = PREP_IE_TARGET_ADDR(prep_elem);
d19b3bf63   Rui Paulo   mac80211: replace...
631
632
  	target_sn = PREP_IE_TARGET_SN(prep_elem);
  	orig_sn = PREP_IE_ORIG_SN(prep_elem);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
633
634
  
  	mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
d19b3bf63   Rui Paulo   mac80211: replace...
635
  		cpu_to_le32(orig_sn), 0, target_addr,
533866b12   Porsch, Marco   mac80211: fix PRE...
636
  		cpu_to_le32(target_sn), next_hop, hopcount,
d19b3bf63   Rui Paulo   mac80211: replace...
637
  		ttl, cpu_to_le32(lifetime), cpu_to_le32(metric),
f698d856f   Jasper Bryant-Greene   replace net_devic...
638
  		0, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
639
  	rcu_read_unlock();
c8a61a7d3   Daniel Walker   mac80211: New sta...
640
641
  
  	sdata->u.mesh.mshstats.fwded_unicast++;
472dbc45d   Johannes Berg   mac80211: split o...
642
  	sdata->u.mesh.mshstats.fwded_frames++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
643
644
645
646
  	return;
  
  fail:
  	rcu_read_unlock();
472dbc45d   Johannes Berg   mac80211: split o...
647
  	sdata->u.mesh.mshstats.dropped_frames_no_route++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
648
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
649
  static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
650
651
  			     struct ieee80211_mgmt *mgmt, u8 *perr_elem)
  {
d611f062f   Rui Paulo   mac80211: update ...
652
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
653
  	struct mesh_path *mpath;
d611f062f   Rui Paulo   mac80211: update ...
654
  	u8 ttl;
d19b3bf63   Rui Paulo   mac80211: replace...
655
  	u8 *ta, *target_addr;
d19b3bf63   Rui Paulo   mac80211: replace...
656
657
  	u32 target_sn;
  	u16 target_rcode;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
658
659
  
  	ta = mgmt->sa;
d611f062f   Rui Paulo   mac80211: update ...
660
661
662
663
664
665
  	ttl = PERR_IE_TTL(perr_elem);
  	if (ttl <= 1) {
  		ifmsh->mshstats.dropped_frames_ttl++;
  		return;
  	}
  	ttl--;
d19b3bf63   Rui Paulo   mac80211: replace...
666
667
668
  	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 ...
669

050ac52cb   Luis Carlos Cobo   mac80211: code fo...
670
  	rcu_read_lock();
d19b3bf63   Rui Paulo   mac80211: replace...
671
  	mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
672
673
674
  	if (mpath) {
  		spin_lock_bh(&mpath->state_lock);
  		if (mpath->flags & MESH_PATH_ACTIVE &&
40b275b69   Johannes Berg   mac80211: sparse ...
675
676
  		    memcmp(ta, next_hop_deref_protected(mpath)->sta.addr,
  							ETH_ALEN) == 0 &&
d19b3bf63   Rui Paulo   mac80211: replace...
677
678
  		    (!(mpath->flags & MESH_PATH_SN_VALID) ||
  		    SN_GT(target_sn, mpath->sn))) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
679
  			mpath->flags &= ~MESH_PATH_ACTIVE;
d19b3bf63   Rui Paulo   mac80211: replace...
680
  			mpath->sn = target_sn;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
681
  			spin_unlock_bh(&mpath->state_lock);
d19b3bf63   Rui Paulo   mac80211: replace...
682
683
  			mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
  					   cpu_to_le16(target_rcode),
15ff63653   Johannes Berg   mac80211: use fix...
684
  					   broadcast_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
685
686
687
688
689
  		} else
  			spin_unlock_bh(&mpath->state_lock);
  	}
  	rcu_read_unlock();
  }
90a5e1699   Rui Paulo   mac80211: impleme...
690
691
692
693
694
695
  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...
696
697
  	u8 ttl, flags, hopcount;
  	u8 *orig_addr;
d19b3bf63   Rui Paulo   mac80211: replace...
698
  	u32 orig_sn, metric;
0507e159a   Javier Cardona   {nl,cfg,mac}80211...
699
  	u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
700
  	bool root_is_gate;
90a5e1699   Rui Paulo   mac80211: impleme...
701

90a5e1699   Rui Paulo   mac80211: impleme...
702
703
704
705
706
707
708
  	ttl = rann->rann_ttl;
  	if (ttl <= 1) {
  		ifmsh->mshstats.dropped_frames_ttl++;
  		return;
  	}
  	ttl--;
  	flags = rann->rann_flags;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
709
  	root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
90a5e1699   Rui Paulo   mac80211: impleme...
710
  	orig_addr = rann->rann_addr;
d19b3bf63   Rui Paulo   mac80211: replace...
711
  	orig_sn = rann->rann_seq;
90a5e1699   Rui Paulo   mac80211: impleme...
712
  	hopcount = rann->rann_hopcount;
a6a58b4f1   Rui Paulo   mac80211: properl...
713
  	hopcount++;
90a5e1699   Rui Paulo   mac80211: impleme...
714
  	metric = rann->rann_metric;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
715
716
717
718
719
720
721
  
  	/*  Ignore our own RANNs */
  	if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
  		return;
  
  	mhwmp_dbg("received RANN from %pM (is_gate=%d)", orig_addr,
  			root_is_gate);
90a5e1699   Rui Paulo   mac80211: impleme...
722
723
724
725
726
727
728
729
730
731
732
  
  	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;
  		}
90a5e1699   Rui Paulo   mac80211: impleme...
733
  	}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
734
735
736
737
738
739
740
741
  
  	if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
  	     time_after(jiffies, mpath->exp_time - 1*HZ)) &&
  	     !(mpath->flags & MESH_PATH_FIXED)) {
  		mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name,
  							       orig_addr);
  		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
  	}
d19b3bf63   Rui Paulo   mac80211: replace...
742
  	if (mpath->sn < orig_sn) {
90a5e1699   Rui Paulo   mac80211: impleme...
743
  		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
d19b3bf63   Rui Paulo   mac80211: replace...
744
  				       cpu_to_le32(orig_sn),
15ff63653   Johannes Berg   mac80211: use fix...
745
  				       0, NULL, 0, broadcast_addr,
0507e159a   Javier Cardona   {nl,cfg,mac}80211...
746
  				       hopcount, ttl, cpu_to_le32(interval),
a6a58b4f1   Rui Paulo   mac80211: properl...
747
  				       cpu_to_le32(metric + mpath->metric),
90a5e1699   Rui Paulo   mac80211: impleme...
748
  				       0, sdata);
d19b3bf63   Rui Paulo   mac80211: replace...
749
  		mpath->sn = orig_sn;
90a5e1699   Rui Paulo   mac80211: impleme...
750
  	}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
751
752
  	if (root_is_gate)
  		mesh_path_add_gate(mpath);
90a5e1699   Rui Paulo   mac80211: impleme...
753
754
  	rcu_read_unlock();
  }
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
755

f698d856f   Jasper Bryant-Greene   replace net_devic...
756
  void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
757
758
759
760
761
762
  			    struct ieee80211_mgmt *mgmt,
  			    size_t len)
  {
  	struct ieee802_11_elems elems;
  	size_t baselen;
  	u32 last_hop_metric;
97091317a   Javier Cardona   mac80211: Fix reg...
763
  	struct sta_info *sta;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
764

9c80d3dc2   Johannes Berg   mac80211: fix act...
765
766
767
  	/* need action_code */
  	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
  		return;
97091317a   Javier Cardona   mac80211: Fix reg...
768
769
770
771
772
773
774
  	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();
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
775
776
777
  	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...
778
779
  	if (elems.preq) {
  		if (elems.preq_len != 37)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
780
781
  			/* Right now we support just 1 destination and no AE */
  			return;
dbb81c428   Rui Paulo   mac80211: allow p...
782
783
784
785
786
787
788
789
  		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...
790
791
  			/* Right now we support no AE */
  			return;
dbb81c428   Rui Paulo   mac80211: allow p...
792
793
794
795
796
797
798
  		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 ...
799
  		if (elems.perr_len != 15)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
800
801
  			/* Right now we support only one destination per PERR */
  			return;
f698d856f   Jasper Bryant-Greene   replace net_devic...
802
  		hwmp_perr_frame_process(sdata, mgmt, elems.perr);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
803
  	}
90a5e1699   Rui Paulo   mac80211: impleme...
804
805
  	if (elems.rann)
  		hwmp_rann_frame_process(sdata, mgmt, elems.rann);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
806
807
808
809
810
811
812
813
814
815
816
817
818
  }
  
  /**
   * 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...
819
  	struct ieee80211_sub_if_data *sdata = mpath->sdata;
472dbc45d   Johannes Berg   mac80211: split o...
820
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
821
  	struct mesh_preq_queue *preq_node;
59615b5f9   Andrey Yurovsky   mac80211: fix all...
822
  	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
823
  	if (!preq_node) {
7646887a5   Javier Cardona   mac80211: improve...
824
  		mhwmp_dbg("could not allocate PREQ node");
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
825
826
  		return;
  	}
987dafad1   Baruch Siach   mac80211/mesh: ma...
827
  	spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
472dbc45d   Johannes Berg   mac80211: split o...
828
  	if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
987dafad1   Baruch Siach   mac80211/mesh: ma...
829
  		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
830
831
  		kfree(preq_node);
  		if (printk_ratelimit())
7646887a5   Javier Cardona   mac80211: improve...
832
  			mhwmp_dbg("PREQ node queue full");
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
833
834
  		return;
  	}
f2dc7989b   Johannes Berg   mac80211: minor c...
835
  	spin_lock(&mpath->state_lock);
f3011cf9d   Javier Cardona   mac80211: Avoid f...
836
  	if (mpath->flags & MESH_PATH_REQ_QUEUED) {
f2dc7989b   Johannes Berg   mac80211: minor c...
837
  		spin_unlock(&mpath->state_lock);
f3011cf9d   Javier Cardona   mac80211: Avoid f...
838
  		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
88d534651   Dan Carpenter   mac80211: memory ...
839
  		kfree(preq_node);
f3011cf9d   Javier Cardona   mac80211: Avoid f...
840
841
  		return;
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
842
843
  	memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
  	preq_node->flags = flags;
f3011cf9d   Javier Cardona   mac80211: Avoid f...
844
  	mpath->flags |= MESH_PATH_REQ_QUEUED;
f2dc7989b   Johannes Berg   mac80211: minor c...
845
  	spin_unlock(&mpath->state_lock);
f3011cf9d   Javier Cardona   mac80211: Avoid f...
846

472dbc45d   Johannes Berg   mac80211: split o...
847
848
  	list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
  	++ifmsh->preq_queue_len;
987dafad1   Baruch Siach   mac80211/mesh: ma...
849
  	spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
850

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

472dbc45d   Johannes Berg   mac80211: split o...
854
  	else if (time_before(jiffies, ifmsh->last_preq)) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
855
856
857
  		/* avoid long wait if did not send preqs for a long time
  		 * and jiffies wrapped around
  		 */
472dbc45d   Johannes Berg   mac80211: split o...
858
  		ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
64592c8fc   Johannes Berg   mac80211: use com...
859
  		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
860
  	} else
472dbc45d   Johannes Berg   mac80211: split o...
861
  		mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
862
863
864
865
866
867
  						min_preq_int_jiff(sdata));
  }
  
  /**
   * mesh_path_start_discovery - launch a path discovery from the PREQ queue
   *
f698d856f   Jasper Bryant-Greene   replace net_devic...
868
   * @sdata: local mesh subif
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
869
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
870
  void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
871
  {
472dbc45d   Johannes Berg   mac80211: split o...
872
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
873
874
  	struct mesh_preq_queue *preq_node;
  	struct mesh_path *mpath;
d19b3bf63   Rui Paulo   mac80211: replace...
875
  	u8 ttl, target_flags;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
876
  	u32 lifetime;
a43816df2   Johannes Berg   mac80211: mesh: f...
877
  	spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
472dbc45d   Johannes Berg   mac80211: split o...
878
879
  	if (!ifmsh->preq_queue_len ||
  		time_before(jiffies, ifmsh->last_preq +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
880
  				min_preq_int_jiff(sdata))) {
a43816df2   Johannes Berg   mac80211: mesh: f...
881
  		spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
882
883
  		return;
  	}
472dbc45d   Johannes Berg   mac80211: split o...
884
  	preq_node = list_first_entry(&ifmsh->preq_queue.list,
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
885
886
  			struct mesh_preq_queue, list);
  	list_del(&preq_node->list);
472dbc45d   Johannes Berg   mac80211: split o...
887
  	--ifmsh->preq_queue_len;
a43816df2   Johannes Berg   mac80211: mesh: f...
888
  	spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
889
890
  
  	rcu_read_lock();
f698d856f   Jasper Bryant-Greene   replace net_devic...
891
  	mpath = mesh_path_lookup(preq_node->dst, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
892
893
894
895
  	if (!mpath)
  		goto enddiscovery;
  
  	spin_lock_bh(&mpath->state_lock);
f3011cf9d   Javier Cardona   mac80211: Avoid f...
896
  	mpath->flags &= ~MESH_PATH_REQ_QUEUED;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
  	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...
913
  	ifmsh->last_preq = jiffies;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
914

d19b3bf63   Rui Paulo   mac80211: replace...
915
  	if (time_after(jiffies, ifmsh->last_sn_update +
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
916
  				net_traversal_jiffies(sdata)) ||
d19b3bf63   Rui Paulo   mac80211: replace...
917
918
919
  	    time_before(jiffies, ifmsh->last_sn_update)) {
  		++ifmsh->sn;
  		sdata->u.mesh.last_sn_update = jiffies;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
920
921
  	}
  	lifetime = default_lifetime(sdata);
45904f216   Javier Cardona   nl80211/mac80211:...
922
  	ttl = sdata->u.mesh.mshcfg.element_ttl;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
923
  	if (ttl == 0) {
472dbc45d   Johannes Berg   mac80211: split o...
924
  		sdata->u.mesh.mshstats.dropped_frames_ttl++;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
925
926
927
928
929
  		spin_unlock_bh(&mpath->state_lock);
  		goto enddiscovery;
  	}
  
  	if (preq_node->flags & PREQ_Q_F_REFRESH)
d19b3bf63   Rui Paulo   mac80211: replace...
930
  		target_flags = MP_F_DO;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
931
  	else
d19b3bf63   Rui Paulo   mac80211: replace...
932
  		target_flags = MP_F_RF;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
933
934
  
  	spin_unlock_bh(&mpath->state_lock);
47846c9b0   Johannes Berg   mac80211: reduce ...
935
  	mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
d19b3bf63   Rui Paulo   mac80211: replace...
936
  			cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
15ff63653   Johannes Berg   mac80211: use fix...
937
  			cpu_to_le32(mpath->sn), broadcast_addr, 0,
aa2b59284   Luis Carlos Cobo   mac80211: clean u...
938
  			ttl, cpu_to_le32(lifetime), 0,
472dbc45d   Johannes Berg   mac80211: split o...
939
  			cpu_to_le32(ifmsh->preq_id++), sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
940
941
942
943
944
945
  	mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
  
  enddiscovery:
  	rcu_read_unlock();
  	kfree(preq_node);
  }
0cfda8519   Thomas Pedersen   mac80211: don't i...
946
947
  /* mesh_nexthop_resolve - lookup next hop for given skb and start path
   * discovery if no forwarding information is found.
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
948
   *
e32f85f7b   Luis Carlos Cobo   mac80211: fix use...
949
   * @skb: 802.11 frame to be sent
f698d856f   Jasper Bryant-Greene   replace net_devic...
950
   * @sdata: network subif the frame will be sent through
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
951
   *
0cfda8519   Thomas Pedersen   mac80211: don't i...
952
953
   * 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.
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
954
   */
0cfda8519   Thomas Pedersen   mac80211: don't i...
955
956
  int mesh_nexthop_resolve(struct sk_buff *skb,
  			 struct ieee80211_sub_if_data *sdata)
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
957
  {
e32f85f7b   Luis Carlos Cobo   mac80211: fix use...
958
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
0cfda8519   Thomas Pedersen   mac80211: don't i...
959
960
961
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  	struct mesh_path *mpath;
  	struct sk_buff *skb_to_free = NULL;
d19b3bf63   Rui Paulo   mac80211: replace...
962
  	u8 *target_addr = hdr->addr3;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
963
964
965
  	int err = 0;
  
  	rcu_read_lock();
0cfda8519   Thomas Pedersen   mac80211: don't i...
966
967
968
  	err = mesh_nexthop_lookup(skb, sdata);
  	if (!err)
  		goto endlookup;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
969

0cfda8519   Thomas Pedersen   mac80211: don't i...
970
971
  	/* no nexthop found, start resolving */
  	mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
972
  	if (!mpath) {
d19b3bf63   Rui Paulo   mac80211: replace...
973
974
  		mesh_path_add(target_addr, sdata);
  		mpath = mesh_path_lookup(target_addr, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
975
  		if (!mpath) {
0cfda8519   Thomas Pedersen   mac80211: don't i...
976
  			mesh_path_discard_frame(skb, sdata);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
977
978
979
980
  			err = -ENOSPC;
  			goto endlookup;
  		}
  	}
0cfda8519   Thomas Pedersen   mac80211: don't i...
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  	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;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1016

0cfda8519   Thomas Pedersen   mac80211: don't i...
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  	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)) &&
  	    !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
  	    !(mpath->flags & MESH_PATH_RESOLVING) &&
  	    !(mpath->flags & MESH_PATH_FIXED))
  		mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1030

0cfda8519   Thomas Pedersen   mac80211: don't i...
1031
1032
1033
1034
1035
  	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;
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1036
1037
1038
1039
1040
1041
1042
1043
1044
  	}
  
  endlookup:
  	rcu_read_unlock();
  	return err;
  }
  
  void mesh_path_timer(unsigned long data)
  {
dea4096bc   Johannes Berg   mac80211: remove ...
1045
1046
  	struct mesh_path *mpath = (void *) data;
  	struct ieee80211_sub_if_data *sdata = mpath->sdata;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1047
  	int ret;
5bb644a0f   Johannes Berg   mac80211: cancel/...
1048

dea4096bc   Johannes Berg   mac80211: remove ...
1049
  	if (sdata->local->quiescing)
5bb644a0f   Johannes Berg   mac80211: cancel/...
1050
  		return;
5bb644a0f   Johannes Berg   mac80211: cancel/...
1051
1052
  
  	spin_lock_bh(&mpath->state_lock);
cfa22c716   Luis Carlos Cobo   mac80211: always ...
1053
  	if (mpath->flags & MESH_PATH_RESOLVED ||
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1054
  			(!(mpath->flags & MESH_PATH_RESOLVING))) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1055
  		mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1056
1057
  		spin_unlock_bh(&mpath->state_lock);
  	} else if (mpath->discovery_retries < max_preq_retries(sdata)) {
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1058
1059
  		++mpath->discovery_retries;
  		mpath->discovery_timeout *= 2;
f3011cf9d   Javier Cardona   mac80211: Avoid f...
1060
  		mpath->flags &= ~MESH_PATH_REQ_QUEUED;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1061
  		spin_unlock_bh(&mpath->state_lock);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1062
1063
1064
1065
  		mesh_queue_preq(mpath, 0);
  	} else {
  		mpath->flags = 0;
  		mpath->exp_time = jiffies;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1066
1067
1068
1069
1070
1071
1072
  		spin_unlock_bh(&mpath->state_lock);
  		if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
  			ret = mesh_path_send_to_gates(mpath);
  			if (ret)
  				mhwmp_dbg("no gate was reachable");
  		} else
  			mesh_path_flush_pending(mpath);
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1073
  	}
050ac52cb   Luis Carlos Cobo   mac80211: code fo...
1074
  }
e304bfd30   Rui Paulo   mac80211: impleme...
1075
1076
1077
1078
1079
  
  void
  mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
0507e159a   Javier Cardona   {nl,cfg,mac}80211...
1080
  	u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
16dd7267f   Javier Cardona   {nl,cfg,mac}80211...
1081
  	u8 flags;
e304bfd30   Rui Paulo   mac80211: impleme...
1082

16dd7267f   Javier Cardona   {nl,cfg,mac}80211...
1083
1084
1085
  	flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
  			? RANN_FLAG_IS_GATE : 0;
  	mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
e304bfd30   Rui Paulo   mac80211: impleme...
1086
  			       cpu_to_le32(++ifmsh->sn),
15ff63653   Johannes Berg   mac80211: use fix...
1087
  			       0, NULL, 0, broadcast_addr,
45904f216   Javier Cardona   nl80211/mac80211:...
1088
  			       0, sdata->u.mesh.mshcfg.element_ttl,
0507e159a   Javier Cardona   {nl,cfg,mac}80211...
1089
  			       cpu_to_le32(interval), 0, 0, sdata);
e304bfd30   Rui Paulo   mac80211: impleme...
1090
  }