Blame view
net/mac80211/mesh_hwmp.c
31.4 KB
050ac52cb mac80211: code fo... |
1 |
/* |
264d9b7d8 mac80211: update ... |
2 |
* Copyright (c) 2008, 2009 open80211s Ltd. |
050ac52cb 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 include cleanup: ... |
9 |
#include <linux/slab.h> |
2cca397f7 mac80211: Defer t... |
10 |
#include "wme.h" |
050ac52cb mac80211: code fo... |
11 |
#include "mesh.h" |
27db2e423 mac80211: add MAC... |
12 |
#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG |
7646887a5 mac80211: improve... |
13 14 15 |
#define mhwmp_dbg(fmt, args...) \ printk(KERN_DEBUG "Mesh HWMP (%s): " fmt " ", sdata->name, ##args) |
27db2e423 mac80211: add MAC... |
16 17 18 |
#else #define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0) #endif |
050ac52cb 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 mac80211: update ... |
31 32 33 34 |
/* Unknown Sequence Number */ #define MP_F_USN 0x01 /* Reason code Present */ #define MP_F_RCODE 0x02 |
050ac52cb mac80211: code fo... |
35 |
|
90a5e1699 mac80211: impleme... |
36 |
static void mesh_queue_preq(struct mesh_path *, u8); |
a00de5d08 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 wireless: use get... |
41 |
return get_unaligned_le32(preq_elem + offset); |
a00de5d08 mac80211: path IE... |
42 |
} |
d611f062f 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 mac80211: code fo... |
49 |
/* HWMP IE processing macros */ |
a00de5d08 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 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 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 treewide: fix pot... |
62 |
#define PREQ_IE_TARGET_SN(x) u32_field_get(x, 33, AE_F_SET(x)) |
a00de5d08 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 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 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 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 mac80211: path IE... |
74 |
|
d611f062f mac80211: update ... |
75 |
#define PERR_IE_TTL(x) (*(x)) |
d19b3bf63 mac80211: replace... |
76 77 |
#define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) #define PERR_IE_TARGET_ADDR(x) (x + 3) |
497888cf6 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 mac80211: code fo... |
80 |
|
050ac52cb mac80211: code fo... |
81 |
#define MSEC_TO_TU(x) (x*1000/1024) |
d19b3bf63 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 mac80211: code fo... |
84 85 |
#define net_traversal_jiffies(s) \ |
472dbc45d mac80211: split o... |
86 |
msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) |
050ac52cb mac80211: code fo... |
87 |
#define default_lifetime(s) \ |
472dbc45d mac80211: split o... |
88 |
MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout) |
050ac52cb mac80211: code fo... |
89 |
#define min_preq_int_jiff(s) \ |
472dbc45d mac80211: split o... |
90 91 |
(msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval)) #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries) |
050ac52cb mac80211: code fo... |
92 |
#define disc_timeout_jiff(s) \ |
472dbc45d mac80211: split o... |
93 |
msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout) |
050ac52cb mac80211: code fo... |
94 95 96 97 |
enum mpath_frame_type { MPATH_PREQ = 0, MPATH_PREP, |
90a5e1699 mac80211: impleme... |
98 99 |
MPATH_PERR, MPATH_RANN |
050ac52cb mac80211: code fo... |
100 |
}; |
15ff63653 mac80211: use fix... |
101 |
static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
050ac52cb mac80211: code fo... |
102 |
static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
d19b3bf63 mac80211: replace... |
103 |
u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target, |
15ff63653 mac80211: use fix... |
104 105 |
__le32 target_sn, const u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, __le32 metric, __le32 preq_id, |
d19b3bf63 mac80211: replace... |
106 |
struct ieee80211_sub_if_data *sdata) |
050ac52cb mac80211: code fo... |
107 |
{ |
f698d856f replace net_devic... |
108 |
struct ieee80211_local *local = sdata->local; |
3b69a9c5f mac80211: comment... |
109 |
struct sk_buff *skb; |
050ac52cb mac80211: code fo... |
110 |
struct ieee80211_mgmt *mgmt; |
3b69a9c5f 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 mac80211: code fo... |
114 |
|
3b69a9c5f mac80211: comment... |
115 116 117 |
skb = dev_alloc_skb(local->hw.extra_tx_headroom + hdr_len + 2 + 37); /* max HWMP IE */ |
050ac52cb mac80211: code fo... |
118 119 120 |
if (!skb) return -1; skb_reserve(skb, local->hw.extra_tx_headroom); |
3b69a9c5f mac80211: comment... |
121 122 |
mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); memset(mgmt, 0, hdr_len); |
e7827a703 mac80211: remove ... |
123 124 |
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); |
050ac52cb mac80211: code fo... |
125 126 |
memcpy(mgmt->da, da, ETH_ALEN); |
47846c9b0 mac80211: reduce ... |
127 |
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
90a5e1699 mac80211: impleme... |
128 |
/* BSSID == SA */ |
47846c9b0 mac80211: reduce ... |
129 |
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
25d49e4d6 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 mac80211: code fo... |
133 134 135 |
switch (action) { case MPATH_PREQ: |
7646887a5 mac80211: improve... |
136 |
mhwmp_dbg("sending PREQ to %pM", target); |
050ac52cb 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 mac80211: improve... |
142 |
mhwmp_dbg("sending PREP to %pM", target); |
050ac52cb mac80211: code fo... |
143 144 145 146 |
ie_len = 31; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; break; |
90a5e1699 mac80211: impleme... |
147 |
case MPATH_RANN: |
7646887a5 mac80211: improve... |
148 |
mhwmp_dbg("sending RANN from %pM", orig_addr); |
90a5e1699 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 mac80211: code fo... |
153 |
default: |
812714d74 mac80211: mesh hw... |
154 |
kfree_skb(skb); |
050ac52cb mac80211: code fo... |
155 156 157 158 159 160 161 |
return -ENOTSUPP; break; } *pos++ = ie_len; *pos++ = flags; *pos++ = hop_count; *pos++ = ttl; |
25d49e4d6 mac80211: update ... |
162 163 164 165 |
if (action == MPATH_PREP) { memcpy(pos, target, ETH_ALEN); pos += ETH_ALEN; memcpy(pos, &target_sn, 4); |
050ac52cb mac80211: code fo... |
166 |
pos += 4; |
25d49e4d6 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 mac80211: impleme... |
175 176 |
pos += 4; } |
25d49e4d6 mac80211: update ... |
177 178 |
memcpy(pos, &lifetime, 4); /* interval for RANN */ pos += 4; |
050ac52cb mac80211: code fo... |
179 180 181 |
memcpy(pos, &metric, 4); pos += 4; if (action == MPATH_PREQ) { |
25d49e4d6 mac80211: update ... |
182 |
*pos++ = 1; /* destination count */ |
d19b3bf63 mac80211: replace... |
183 |
*pos++ = target_flags; |
d19b3bf63 mac80211: replace... |
184 |
memcpy(pos, target, ETH_ALEN); |
90a5e1699 mac80211: impleme... |
185 |
pos += ETH_ALEN; |
d19b3bf63 mac80211: replace... |
186 |
memcpy(pos, &target_sn, 4); |
25d49e4d6 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 mac80211: impleme... |
193 |
} |
050ac52cb mac80211: code fo... |
194 |
|
62ae67be3 mac80211: remove ... |
195 |
ieee80211_tx_skb(sdata, skb); |
050ac52cb mac80211: code fo... |
196 197 |
return 0; } |
2cca397f7 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 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 mac80211: Mesh da... |
215 |
ieee80211_set_qos_hdr(sdata, skb); |
2cca397f7 mac80211: Defer t... |
216 |
} |
050ac52cb mac80211: code fo... |
217 218 219 |
/** * mesh_send_path error - Sends a PERR mesh management frame * |
d19b3bf63 mac80211: replace... |
220 221 222 |
* @target: broken destination * @target_sn: SN of the broken destination * @target_rcode: reason code for this PERR |
050ac52cb mac80211: code fo... |
223 |
* @ra: node this frame is addressed to |
2cca397f7 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 mac80211: code fo... |
228 |
*/ |
d19b3bf63 mac80211: replace... |
229 |
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, |
15ff63653 mac80211: use fix... |
230 231 |
__le16 target_rcode, const u8 *ra, struct ieee80211_sub_if_data *sdata) |
050ac52cb mac80211: code fo... |
232 |
{ |
f698d856f replace net_devic... |
233 |
struct ieee80211_local *local = sdata->local; |
3b69a9c5f mac80211: comment... |
234 |
struct sk_buff *skb; |
dca7e9430 {nl,cfg,mac}80211... |
235 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
050ac52cb mac80211: code fo... |
236 |
struct ieee80211_mgmt *mgmt; |
3b69a9c5f 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 mac80211: code fo... |
240 |
|
dca7e9430 {nl,cfg,mac}80211... |
241 242 |
if (time_before(jiffies, ifmsh->next_perr)) return -EAGAIN; |
3b69a9c5f mac80211: comment... |
243 244 245 |
skb = dev_alloc_skb(local->hw.extra_tx_headroom + hdr_len + 2 + 15 /* PERR IE */); |
050ac52cb mac80211: code fo... |
246 247 |
if (!skb) return -1; |
2cca397f7 mac80211: Defer t... |
248 |
skb_reserve(skb, local->tx_headroom + local->hw.extra_tx_headroom); |
3b69a9c5f mac80211: comment... |
249 250 |
mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); memset(mgmt, 0, hdr_len); |
e7827a703 mac80211: remove ... |
251 252 |
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); |
050ac52cb mac80211: code fo... |
253 254 |
memcpy(mgmt->da, ra, ETH_ALEN); |
47846c9b0 mac80211: reduce ... |
255 |
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
25d49e4d6 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 mac80211: update ... |
261 |
ie_len = 15; |
050ac52cb mac80211: code fo... |
262 263 264 |
pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PERR; *pos++ = ie_len; |
d611f062f mac80211: update ... |
265 |
/* ttl */ |
45904f216 nl80211/mac80211:... |
266 |
*pos++ = ttl; |
050ac52cb mac80211: code fo... |
267 268 |
/* number of destinations */ *pos++ = 1; |
d611f062f 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 mac80211: replace... |
274 |
if (!target_sn) |
d611f062f mac80211: update ... |
275 |
*pos |= MP_F_USN; |
d19b3bf63 mac80211: replace... |
276 |
if (target_rcode) |
d611f062f mac80211: update ... |
277 278 |
*pos |= MP_F_RCODE; pos++; |
d19b3bf63 mac80211: replace... |
279 |
memcpy(pos, target, ETH_ALEN); |
050ac52cb mac80211: code fo... |
280 |
pos += ETH_ALEN; |
d19b3bf63 mac80211: replace... |
281 |
memcpy(pos, &target_sn, 4); |
d611f062f mac80211: update ... |
282 |
pos += 4; |
d19b3bf63 mac80211: replace... |
283 |
memcpy(pos, &target_rcode, 2); |
050ac52cb mac80211: code fo... |
284 |
|
2cca397f7 mac80211: Defer t... |
285 286 |
/* see note in function header */ prepare_frame_for_deferred_tx(sdata, skb); |
dca7e9430 {nl,cfg,mac}80211... |
287 288 |
ifmsh->next_perr = TU_TO_EXP_TIME( ifmsh->mshcfg.dot11MeshHWMPperrMinInterval); |
2cca397f7 mac80211: Defer t... |
289 |
ieee80211_add_pending_skb(local, skb); |
050ac52cb mac80211: code fo... |
290 291 |
return 0; } |
bfc32e6a9 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 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 mac80211/drivers:... |
325 326 327 |
if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) return MAX_METRIC; |
050ac52cb 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 mac80211/drivers:... |
333 |
rate = sband->bitrates[sta->last_tx_rate.idx].bitrate; |
050ac52cb 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 replace net_devic... |
343 |
* @sdata: local mesh subif |
050ac52cb 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 mac80211: trivial... |
348 |
* transmitter of a HWMP PREQ or PREP frame. |
050ac52cb 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 replace net_devic... |
356 |
static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, |
050ac52cb mac80211: code fo... |
357 |
struct ieee80211_mgmt *mgmt, |
dbb81c428 mac80211: allow p... |
358 |
u8 *hwmp_ie, enum mpath_frame_type action) |
050ac52cb mac80211: code fo... |
359 |
{ |
f698d856f replace net_devic... |
360 |
struct ieee80211_local *local = sdata->local; |
050ac52cb mac80211: code fo... |
361 362 363 364 |
struct mesh_path *mpath; struct sta_info *sta; bool fresh_info; u8 *orig_addr, *ta; |
d19b3bf63 mac80211: replace... |
365 |
u32 orig_sn, orig_metric; |
050ac52cb mac80211: code fo... |
366 367 368 |
unsigned long orig_lifetime, exp_time; u32 last_hop_metric, new_metric; bool process = true; |
050ac52cb mac80211: code fo... |
369 370 |
rcu_read_lock(); |
abe60632f mac80211: make st... |
371 |
sta = sta_info_get(sdata, mgmt->sa); |
dc0b0f7d1 mac80211: mesh hw... |
372 373 |
if (!sta) { rcu_read_unlock(); |
050ac52cb mac80211: code fo... |
374 |
return 0; |
dc0b0f7d1 mac80211: mesh hw... |
375 |
} |
050ac52cb 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 mac80211: replace... |
384 |
orig_sn = PREQ_IE_ORIG_SN(hwmp_ie); |
050ac52cb 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 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 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 mac80211: fix swi... |
394 395 |
orig_addr = PREP_IE_TARGET_ADDR(hwmp_ie); orig_sn = PREP_IE_TARGET_SN(hwmp_ie); |
050ac52cb mac80211: code fo... |
396 397 398 399 |
orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); orig_metric = PREP_IE_METRIC(hwmp_ie); break; default: |
dc0b0f7d1 mac80211: mesh hw... |
400 |
rcu_read_unlock(); |
050ac52cb 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 mac80211: reduce ... |
407 |
if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) { |
050ac52cb 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 replace net_devic... |
414 |
mpath = mesh_path_lookup(orig_addr, sdata); |
050ac52cb 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 mac80211: replace... |
420 421 422 |
(mpath->flags & MESH_PATH_SN_VALID)) { if (SN_GT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && |
533866b12 mac80211: fix PRE... |
423 |
new_metric >= mpath->metric)) { |
050ac52cb mac80211: code fo... |
424 425 426 427 428 |
process = false; fresh_info = false; } } } else { |
f698d856f replace net_devic... |
429 430 |
mesh_path_add(orig_addr, sdata); mpath = mesh_path_lookup(orig_addr, sdata); |
050ac52cb mac80211: code fo... |
431 432 |
if (!mpath) { rcu_read_unlock(); |
050ac52cb 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 mac80211: replace... |
440 |
mpath->flags |= MESH_PATH_SN_VALID; |
050ac52cb mac80211: code fo... |
441 |
mpath->metric = new_metric; |
d19b3bf63 mac80211: replace... |
442 |
mpath->sn = orig_sn; |
050ac52cb 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 replace net_devic... |
461 |
mpath = mesh_path_lookup(ta, sdata); |
050ac52cb 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 replace net_devic... |
469 470 |
mesh_path_add(ta, sdata); mpath = mesh_path_lookup(ta, sdata); |
050ac52cb mac80211: code fo... |
471 472 |
if (!mpath) { rcu_read_unlock(); |
050ac52cb 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 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 mac80211: code fo... |
489 490 491 492 |
rcu_read_unlock(); return process ? new_metric : 0; } |
f698d856f replace net_devic... |
493 |
static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, |
050ac52cb mac80211: code fo... |
494 |
struct ieee80211_mgmt *mgmt, |
57ef5ddb4 mac80211: Mark a ... |
495 496 |
u8 *preq_elem, u32 metric) { |
472dbc45d mac80211: split o... |
497 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
050ac52cb mac80211: code fo... |
498 |
struct mesh_path *mpath; |
d19b3bf63 mac80211: replace... |
499 500 501 |
u8 *target_addr, *orig_addr; u8 target_flags, ttl; u32 orig_sn, target_sn, lifetime; |
050ac52cb mac80211: code fo... |
502 503 |
bool reply = false; bool forward = true; |
d19b3bf63 mac80211: replace... |
504 505 |
/* Update target SN, if present */ target_addr = PREQ_IE_TARGET_ADDR(preq_elem); |
050ac52cb mac80211: code fo... |
506 |
orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); |
d19b3bf63 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 mac80211: code fo... |
510 |
|
7646887a5 mac80211: improve... |
511 |
mhwmp_dbg("received PREQ from %pM", orig_addr); |
27db2e423 mac80211: add MAC... |
512 |
|
47846c9b0 mac80211: reduce ... |
513 |
if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) { |
7646887a5 mac80211: improve... |
514 |
mhwmp_dbg("PREQ is for us"); |
050ac52cb mac80211: code fo... |
515 516 517 |
forward = false; reply = true; metric = 0; |
d19b3bf63 mac80211: replace... |
518 |
if (time_after(jiffies, ifmsh->last_sn_update + |
050ac52cb mac80211: code fo... |
519 |
net_traversal_jiffies(sdata)) || |
d19b3bf63 mac80211: replace... |
520 521 522 |
time_before(jiffies, ifmsh->last_sn_update)) { target_sn = ++ifmsh->sn; ifmsh->last_sn_update = jiffies; |
050ac52cb mac80211: code fo... |
523 524 525 |
} } else { rcu_read_lock(); |
d19b3bf63 mac80211: replace... |
526 |
mpath = mesh_path_lookup(target_addr, sdata); |
050ac52cb mac80211: code fo... |
527 |
if (mpath) { |
d19b3bf63 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 mac80211: code fo... |
533 534 535 |
(mpath->flags & MESH_PATH_ACTIVE)) { reply = true; metric = mpath->metric; |
d19b3bf63 mac80211: replace... |
536 537 538 |
target_sn = mpath->sn; if (target_flags & MP_F_RF) target_flags |= MP_F_DO; |
050ac52cb 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 nl80211/mac80211:... |
548 |
ttl = ifmsh->mshcfg.element_ttl; |
27db2e423 mac80211: add MAC... |
549 |
if (ttl != 0) { |
7646887a5 mac80211: improve... |
550 |
mhwmp_dbg("replying to the PREQ"); |
3c26f1f68 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 mac80211: clean u... |
554 |
cpu_to_le32(lifetime), cpu_to_le32(metric), |
f698d856f replace net_devic... |
555 |
0, sdata); |
27db2e423 mac80211: add MAC... |
556 |
} else |
472dbc45d mac80211: split o... |
557 |
ifmsh->mshstats.dropped_frames_ttl++; |
050ac52cb 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 mac80211: split o... |
567 |
ifmsh->mshstats.dropped_frames_ttl++; |
050ac52cb mac80211: code fo... |
568 569 |
return; } |
7646887a5 mac80211: improve... |
570 |
mhwmp_dbg("forwarding the PREQ from %pM", orig_addr); |
050ac52cb 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 mac80211: replace... |
576 |
cpu_to_le32(orig_sn), target_flags, target_addr, |
15ff63653 mac80211: use fix... |
577 |
cpu_to_le32(target_sn), broadcast_addr, |
aa2b59284 mac80211: clean u... |
578 579 |
hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), |
f698d856f replace net_devic... |
580 |
sdata); |
c8a61a7d3 mac80211: New sta... |
581 |
ifmsh->mshstats.fwded_mcast++; |
472dbc45d mac80211: split o... |
582 |
ifmsh->mshstats.fwded_frames++; |
050ac52cb mac80211: code fo... |
583 584 |
} } |
40b275b69 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 replace net_devic... |
591 |
static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, |
050ac52cb mac80211: code fo... |
592 593 594 |
struct ieee80211_mgmt *mgmt, u8 *prep_elem, u32 metric) { |
050ac52cb mac80211: code fo... |
595 |
struct mesh_path *mpath; |
d19b3bf63 mac80211: replace... |
596 |
u8 *target_addr, *orig_addr; |
050ac52cb mac80211: code fo... |
597 598 |
u8 ttl, hopcount, flags; u8 next_hop[ETH_ALEN]; |
d19b3bf63 mac80211: replace... |
599 |
u32 target_sn, orig_sn, lifetime; |
050ac52cb mac80211: code fo... |
600 |
|
7646887a5 mac80211: improve... |
601 |
mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem)); |
dbb81c428 mac80211: allow p... |
602 |
|
3c26f1f68 mac80211: fix swi... |
603 604 |
orig_addr = PREP_IE_ORIG_ADDR(prep_elem); if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) |
050ac52cb mac80211: code fo... |
605 606 607 608 609 |
/* destination, no forwarding required */ return; ttl = PREP_IE_TTL(prep_elem); if (ttl <= 1) { |
472dbc45d mac80211: split o... |
610 |
sdata->u.mesh.mshstats.dropped_frames_ttl++; |
050ac52cb mac80211: code fo... |
611 612 613 614 |
return; } rcu_read_lock(); |
3c26f1f68 mac80211: fix swi... |
615 |
mpath = mesh_path_lookup(orig_addr, sdata); |
050ac52cb 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 mac80211: sparse ... |
624 |
memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN); |
050ac52cb 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 mac80211: fix swi... |
630 |
target_addr = PREP_IE_TARGET_ADDR(prep_elem); |
d19b3bf63 mac80211: replace... |
631 632 |
target_sn = PREP_IE_TARGET_SN(prep_elem); orig_sn = PREP_IE_ORIG_SN(prep_elem); |
050ac52cb mac80211: code fo... |
633 634 |
mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, |
d19b3bf63 mac80211: replace... |
635 |
cpu_to_le32(orig_sn), 0, target_addr, |
533866b12 mac80211: fix PRE... |
636 |
cpu_to_le32(target_sn), next_hop, hopcount, |
d19b3bf63 mac80211: replace... |
637 |
ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), |
f698d856f replace net_devic... |
638 |
0, sdata); |
050ac52cb mac80211: code fo... |
639 |
rcu_read_unlock(); |
c8a61a7d3 mac80211: New sta... |
640 641 |
sdata->u.mesh.mshstats.fwded_unicast++; |
472dbc45d mac80211: split o... |
642 |
sdata->u.mesh.mshstats.fwded_frames++; |
050ac52cb mac80211: code fo... |
643 644 645 646 |
return; fail: rcu_read_unlock(); |
472dbc45d mac80211: split o... |
647 |
sdata->u.mesh.mshstats.dropped_frames_no_route++; |
050ac52cb mac80211: code fo... |
648 |
} |
f698d856f replace net_devic... |
649 |
static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, |
050ac52cb mac80211: code fo... |
650 651 |
struct ieee80211_mgmt *mgmt, u8 *perr_elem) { |
d611f062f mac80211: update ... |
652 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
050ac52cb mac80211: code fo... |
653 |
struct mesh_path *mpath; |
d611f062f mac80211: update ... |
654 |
u8 ttl; |
d19b3bf63 mac80211: replace... |
655 |
u8 *ta, *target_addr; |
d19b3bf63 mac80211: replace... |
656 657 |
u32 target_sn; u16 target_rcode; |
050ac52cb mac80211: code fo... |
658 659 |
ta = mgmt->sa; |
d611f062f 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 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 mac80211: update ... |
669 |
|
050ac52cb mac80211: code fo... |
670 |
rcu_read_lock(); |
d19b3bf63 mac80211: replace... |
671 |
mpath = mesh_path_lookup(target_addr, sdata); |
050ac52cb mac80211: code fo... |
672 673 674 |
if (mpath) { spin_lock_bh(&mpath->state_lock); if (mpath->flags & MESH_PATH_ACTIVE && |
40b275b69 mac80211: sparse ... |
675 676 |
memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN) == 0 && |
d19b3bf63 mac80211: replace... |
677 678 |
(!(mpath->flags & MESH_PATH_SN_VALID) || SN_GT(target_sn, mpath->sn))) { |
050ac52cb mac80211: code fo... |
679 |
mpath->flags &= ~MESH_PATH_ACTIVE; |
d19b3bf63 mac80211: replace... |
680 |
mpath->sn = target_sn; |
050ac52cb mac80211: code fo... |
681 |
spin_unlock_bh(&mpath->state_lock); |
d19b3bf63 mac80211: replace... |
682 683 |
mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), cpu_to_le16(target_rcode), |
15ff63653 mac80211: use fix... |
684 |
broadcast_addr, sdata); |
050ac52cb mac80211: code fo... |
685 686 687 688 689 |
} else spin_unlock_bh(&mpath->state_lock); } rcu_read_unlock(); } |
90a5e1699 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 mac80211: impleme... |
696 697 |
u8 ttl, flags, hopcount; u8 *orig_addr; |
d19b3bf63 mac80211: replace... |
698 |
u32 orig_sn, metric; |
0507e159a {nl,cfg,mac}80211... |
699 |
u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; |
5ee68e5b3 mac80211: mesh ga... |
700 |
bool root_is_gate; |
90a5e1699 mac80211: impleme... |
701 |
|
90a5e1699 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 mac80211: mesh ga... |
709 |
root_is_gate = !!(flags & RANN_FLAG_IS_GATE); |
90a5e1699 mac80211: impleme... |
710 |
orig_addr = rann->rann_addr; |
d19b3bf63 mac80211: replace... |
711 |
orig_sn = rann->rann_seq; |
90a5e1699 mac80211: impleme... |
712 |
hopcount = rann->rann_hopcount; |
a6a58b4f1 mac80211: properl... |
713 |
hopcount++; |
90a5e1699 mac80211: impleme... |
714 |
metric = rann->rann_metric; |
5ee68e5b3 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 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 mac80211: impleme... |
733 |
} |
5ee68e5b3 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 mac80211: replace... |
742 |
if (mpath->sn < orig_sn) { |
90a5e1699 mac80211: impleme... |
743 |
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, |
d19b3bf63 mac80211: replace... |
744 |
cpu_to_le32(orig_sn), |
15ff63653 mac80211: use fix... |
745 |
0, NULL, 0, broadcast_addr, |
0507e159a {nl,cfg,mac}80211... |
746 |
hopcount, ttl, cpu_to_le32(interval), |
a6a58b4f1 mac80211: properl... |
747 |
cpu_to_le32(metric + mpath->metric), |
90a5e1699 mac80211: impleme... |
748 |
0, sdata); |
d19b3bf63 mac80211: replace... |
749 |
mpath->sn = orig_sn; |
90a5e1699 mac80211: impleme... |
750 |
} |
5ee68e5b3 mac80211: mesh ga... |
751 752 |
if (root_is_gate) mesh_path_add_gate(mpath); |
90a5e1699 mac80211: impleme... |
753 754 |
rcu_read_unlock(); } |
050ac52cb mac80211: code fo... |
755 |
|
f698d856f replace net_devic... |
756 |
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
050ac52cb 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 mac80211: Fix reg... |
763 |
struct sta_info *sta; |
050ac52cb mac80211: code fo... |
764 |
|
9c80d3dc2 mac80211: fix act... |
765 766 767 |
/* need action_code */ if (len < IEEE80211_MIN_ACTION_SIZE + 1) return; |
97091317a 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 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 mac80211: allow p... |
778 779 |
if (elems.preq) { if (elems.preq_len != 37) |
050ac52cb mac80211: code fo... |
780 781 |
/* Right now we support just 1 destination and no AE */ return; |
dbb81c428 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 mac80211: code fo... |
790 791 |
/* Right now we support no AE */ return; |
dbb81c428 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 mac80211: update ... |
799 |
if (elems.perr_len != 15) |
050ac52cb mac80211: code fo... |
800 801 |
/* Right now we support only one destination per PERR */ return; |
f698d856f replace net_devic... |
802 |
hwmp_perr_frame_process(sdata, mgmt, elems.perr); |
050ac52cb mac80211: code fo... |
803 |
} |
90a5e1699 mac80211: impleme... |
804 805 |
if (elems.rann) hwmp_rann_frame_process(sdata, mgmt, elems.rann); |
050ac52cb 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 replace net_devic... |
819 |
struct ieee80211_sub_if_data *sdata = mpath->sdata; |
472dbc45d mac80211: split o... |
820 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
050ac52cb mac80211: code fo... |
821 |
struct mesh_preq_queue *preq_node; |
59615b5f9 mac80211: fix all... |
822 |
preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); |
050ac52cb mac80211: code fo... |
823 |
if (!preq_node) { |
7646887a5 mac80211: improve... |
824 |
mhwmp_dbg("could not allocate PREQ node"); |
050ac52cb mac80211: code fo... |
825 826 |
return; } |
987dafad1 mac80211/mesh: ma... |
827 |
spin_lock_bh(&ifmsh->mesh_preq_queue_lock); |
472dbc45d mac80211: split o... |
828 |
if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) { |
987dafad1 mac80211/mesh: ma... |
829 |
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
050ac52cb mac80211: code fo... |
830 831 |
kfree(preq_node); if (printk_ratelimit()) |
7646887a5 mac80211: improve... |
832 |
mhwmp_dbg("PREQ node queue full"); |
050ac52cb mac80211: code fo... |
833 834 |
return; } |
f2dc7989b mac80211: minor c... |
835 |
spin_lock(&mpath->state_lock); |
f3011cf9d mac80211: Avoid f... |
836 |
if (mpath->flags & MESH_PATH_REQ_QUEUED) { |
f2dc7989b mac80211: minor c... |
837 |
spin_unlock(&mpath->state_lock); |
f3011cf9d mac80211: Avoid f... |
838 |
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
88d534651 mac80211: memory ... |
839 |
kfree(preq_node); |
f3011cf9d mac80211: Avoid f... |
840 841 |
return; } |
050ac52cb mac80211: code fo... |
842 843 |
memcpy(preq_node->dst, mpath->dst, ETH_ALEN); preq_node->flags = flags; |
f3011cf9d mac80211: Avoid f... |
844 |
mpath->flags |= MESH_PATH_REQ_QUEUED; |
f2dc7989b mac80211: minor c... |
845 |
spin_unlock(&mpath->state_lock); |
f3011cf9d mac80211: Avoid f... |
846 |
|
472dbc45d mac80211: split o... |
847 848 |
list_add_tail(&preq_node->list, &ifmsh->preq_queue.list); ++ifmsh->preq_queue_len; |
987dafad1 mac80211/mesh: ma... |
849 |
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
050ac52cb mac80211: code fo... |
850 |
|
472dbc45d mac80211: split o... |
851 |
if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) |
64592c8fc mac80211: use com... |
852 |
ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
050ac52cb mac80211: code fo... |
853 |
|
472dbc45d mac80211: split o... |
854 |
else if (time_before(jiffies, ifmsh->last_preq)) { |
050ac52cb mac80211: code fo... |
855 856 857 |
/* avoid long wait if did not send preqs for a long time * and jiffies wrapped around */ |
472dbc45d mac80211: split o... |
858 |
ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; |
64592c8fc mac80211: use com... |
859 |
ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
050ac52cb mac80211: code fo... |
860 |
} else |
472dbc45d mac80211: split o... |
861 |
mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + |
050ac52cb 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 replace net_devic... |
868 |
* @sdata: local mesh subif |
050ac52cb mac80211: code fo... |
869 |
*/ |
f698d856f replace net_devic... |
870 |
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) |
050ac52cb mac80211: code fo... |
871 |
{ |
472dbc45d mac80211: split o... |
872 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
050ac52cb mac80211: code fo... |
873 874 |
struct mesh_preq_queue *preq_node; struct mesh_path *mpath; |
d19b3bf63 mac80211: replace... |
875 |
u8 ttl, target_flags; |
050ac52cb mac80211: code fo... |
876 |
u32 lifetime; |
a43816df2 mac80211: mesh: f... |
877 |
spin_lock_bh(&ifmsh->mesh_preq_queue_lock); |
472dbc45d mac80211: split o... |
878 879 |
if (!ifmsh->preq_queue_len || time_before(jiffies, ifmsh->last_preq + |
050ac52cb mac80211: code fo... |
880 |
min_preq_int_jiff(sdata))) { |
a43816df2 mac80211: mesh: f... |
881 |
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
050ac52cb mac80211: code fo... |
882 883 |
return; } |
472dbc45d mac80211: split o... |
884 |
preq_node = list_first_entry(&ifmsh->preq_queue.list, |
050ac52cb mac80211: code fo... |
885 886 |
struct mesh_preq_queue, list); list_del(&preq_node->list); |
472dbc45d mac80211: split o... |
887 |
--ifmsh->preq_queue_len; |
a43816df2 mac80211: mesh: f... |
888 |
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
050ac52cb mac80211: code fo... |
889 890 |
rcu_read_lock(); |
f698d856f replace net_devic... |
891 |
mpath = mesh_path_lookup(preq_node->dst, sdata); |
050ac52cb mac80211: code fo... |
892 893 894 895 |
if (!mpath) goto enddiscovery; spin_lock_bh(&mpath->state_lock); |
f3011cf9d mac80211: Avoid f... |
896 |
mpath->flags &= ~MESH_PATH_REQ_QUEUED; |
050ac52cb 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 mac80211: split o... |
913 |
ifmsh->last_preq = jiffies; |
050ac52cb mac80211: code fo... |
914 |
|
d19b3bf63 mac80211: replace... |
915 |
if (time_after(jiffies, ifmsh->last_sn_update + |
050ac52cb mac80211: code fo... |
916 |
net_traversal_jiffies(sdata)) || |
d19b3bf63 mac80211: replace... |
917 918 919 |
time_before(jiffies, ifmsh->last_sn_update)) { ++ifmsh->sn; sdata->u.mesh.last_sn_update = jiffies; |
050ac52cb mac80211: code fo... |
920 921 |
} lifetime = default_lifetime(sdata); |
45904f216 nl80211/mac80211:... |
922 |
ttl = sdata->u.mesh.mshcfg.element_ttl; |
050ac52cb mac80211: code fo... |
923 |
if (ttl == 0) { |
472dbc45d mac80211: split o... |
924 |
sdata->u.mesh.mshstats.dropped_frames_ttl++; |
050ac52cb 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 mac80211: replace... |
930 |
target_flags = MP_F_DO; |
050ac52cb mac80211: code fo... |
931 |
else |
d19b3bf63 mac80211: replace... |
932 |
target_flags = MP_F_RF; |
050ac52cb mac80211: code fo... |
933 934 |
spin_unlock_bh(&mpath->state_lock); |
47846c9b0 mac80211: reduce ... |
935 |
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, |
d19b3bf63 mac80211: replace... |
936 |
cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, |
15ff63653 mac80211: use fix... |
937 |
cpu_to_le32(mpath->sn), broadcast_addr, 0, |
aa2b59284 mac80211: clean u... |
938 |
ttl, cpu_to_le32(lifetime), 0, |
472dbc45d mac80211: split o... |
939 |
cpu_to_le32(ifmsh->preq_id++), sdata); |
050ac52cb 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 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 mac80211: code fo... |
948 |
* |
e32f85f7b mac80211: fix use... |
949 |
* @skb: 802.11 frame to be sent |
f698d856f replace net_devic... |
950 |
* @sdata: network subif the frame will be sent through |
050ac52cb mac80211: code fo... |
951 |
* |
0cfda8519 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 mac80211: code fo... |
954 |
*/ |
0cfda8519 mac80211: don't i... |
955 956 |
int mesh_nexthop_resolve(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) |
050ac52cb mac80211: code fo... |
957 |
{ |
e32f85f7b mac80211: fix use... |
958 |
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
0cfda8519 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 mac80211: replace... |
962 |
u8 *target_addr = hdr->addr3; |
050ac52cb mac80211: code fo... |
963 964 965 |
int err = 0; rcu_read_lock(); |
0cfda8519 mac80211: don't i... |
966 967 968 |
err = mesh_nexthop_lookup(skb, sdata); if (!err) goto endlookup; |
050ac52cb mac80211: code fo... |
969 |
|
0cfda8519 mac80211: don't i... |
970 971 |
/* no nexthop found, start resolving */ mpath = mesh_path_lookup(target_addr, sdata); |
050ac52cb mac80211: code fo... |
972 |
if (!mpath) { |
d19b3bf63 mac80211: replace... |
973 974 |
mesh_path_add(target_addr, sdata); mpath = mesh_path_lookup(target_addr, sdata); |
050ac52cb mac80211: code fo... |
975 |
if (!mpath) { |
0cfda8519 mac80211: don't i... |
976 |
mesh_path_discard_frame(skb, sdata); |
050ac52cb mac80211: code fo... |
977 978 979 980 |
err = -ENOSPC; goto endlookup; } } |
0cfda8519 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 mac80211: code fo... |
1016 |
|
0cfda8519 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 mac80211: code fo... |
1030 |
|
0cfda8519 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 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 mac80211: remove ... |
1045 1046 |
struct mesh_path *mpath = (void *) data; struct ieee80211_sub_if_data *sdata = mpath->sdata; |
5ee68e5b3 mac80211: mesh ga... |
1047 |
int ret; |
5bb644a0f mac80211: cancel/... |
1048 |
|
dea4096bc mac80211: remove ... |
1049 |
if (sdata->local->quiescing) |
5bb644a0f mac80211: cancel/... |
1050 |
return; |
5bb644a0f mac80211: cancel/... |
1051 1052 |
spin_lock_bh(&mpath->state_lock); |
cfa22c716 mac80211: always ... |
1053 |
if (mpath->flags & MESH_PATH_RESOLVED || |
5ee68e5b3 mac80211: mesh ga... |
1054 |
(!(mpath->flags & MESH_PATH_RESOLVING))) { |
050ac52cb mac80211: code fo... |
1055 |
mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); |
5ee68e5b3 mac80211: mesh ga... |
1056 1057 |
spin_unlock_bh(&mpath->state_lock); } else if (mpath->discovery_retries < max_preq_retries(sdata)) { |
050ac52cb mac80211: code fo... |
1058 1059 |
++mpath->discovery_retries; mpath->discovery_timeout *= 2; |
f3011cf9d mac80211: Avoid f... |
1060 |
mpath->flags &= ~MESH_PATH_REQ_QUEUED; |
5ee68e5b3 mac80211: mesh ga... |
1061 |
spin_unlock_bh(&mpath->state_lock); |
050ac52cb mac80211: code fo... |
1062 1063 1064 1065 |
mesh_queue_preq(mpath, 0); } else { mpath->flags = 0; mpath->exp_time = jiffies; |
5ee68e5b3 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 mac80211: code fo... |
1073 |
} |
050ac52cb mac80211: code fo... |
1074 |
} |
e304bfd30 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 {nl,cfg,mac}80211... |
1080 |
u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; |
16dd7267f {nl,cfg,mac}80211... |
1081 |
u8 flags; |
e304bfd30 mac80211: impleme... |
1082 |
|
16dd7267f {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 mac80211: impleme... |
1086 |
cpu_to_le32(++ifmsh->sn), |
15ff63653 mac80211: use fix... |
1087 |
0, NULL, 0, broadcast_addr, |
45904f216 nl80211/mac80211:... |
1088 |
0, sdata->u.mesh.mshcfg.element_ttl, |
0507e159a {nl,cfg,mac}80211... |
1089 |
cpu_to_le32(interval), 0, 0, sdata); |
e304bfd30 mac80211: impleme... |
1090 |
} |