aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/mesh.h9
-rw-r--r--net/mac80211/mesh_hwmp.c58
-rw-r--r--net/mac80211/mesh_pathtbl.c6
3 files changed, 60 insertions, 13 deletions
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 2fd3e200a063..1d534c702406 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -210,6 +210,11 @@ struct mesh_rmc {
210#define MESH_PATH_SEL_CATEGORY 32 210#define MESH_PATH_SEL_CATEGORY 32
211#define MESH_PATH_SEL_ACTION 0 211#define MESH_PATH_SEL_ACTION 0
212 212
213/* PERR reason codes */
214#define PEER_RCODE_UNSPECIFIED 11
215#define PERR_RCODE_NO_ROUTE 12
216#define PERR_RCODE_DEST_UNREACH 13
217
213/* Public interfaces */ 218/* Public interfaces */
214/* Various */ 219/* Various */
215int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, 220int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
@@ -275,8 +280,8 @@ void mesh_mpp_table_grow(void);
275u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, 280u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
276 struct mesh_table *tbl); 281 struct mesh_table *tbl);
277/* Mesh paths */ 282/* Mesh paths */
278int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, 283int mesh_path_error_tx(u8 ttl, u8 *dest, __le32 dest_dsn, __le16 dest_rcode,
279 struct ieee80211_sub_if_data *sdata); 284 u8 *ra, struct ieee80211_sub_if_data *sdata);
280void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); 285void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
281void mesh_path_flush_pending(struct mesh_path *mpath); 286void mesh_path_flush_pending(struct mesh_path *mpath);
282void mesh_path_tx_pending(struct mesh_path *mpath); 287void mesh_path_tx_pending(struct mesh_path *mpath);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 7b9dd87cf9f2..eb4180bff575 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -27,6 +27,10 @@
27#define MP_F_DO 0x1 27#define MP_F_DO 0x1
28/* Reply and forward */ 28/* Reply and forward */
29#define MP_F_RF 0x2 29#define MP_F_RF 0x2
30/* Unknown Sequence Number */
31#define MP_F_USN 0x01
32/* Reason code Present */
33#define MP_F_RCODE 0x02
30 34
31static void mesh_queue_preq(struct mesh_path *, u8); 35static void mesh_queue_preq(struct mesh_path *, u8);
32 36
@@ -37,6 +41,13 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
37 return get_unaligned_le32(preq_elem + offset); 41 return get_unaligned_le32(preq_elem + offset);
38} 42}
39 43
44static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
45{
46 if (ae)
47 offset += 6;
48 return get_unaligned_le16(preq_elem + offset);
49}
50
40/* HWMP IE processing macros */ 51/* HWMP IE processing macros */
41#define AE_F (1<<6) 52#define AE_F (1<<6)
42#define AE_F_SET(x) (*x & AE_F) 53#define AE_F_SET(x) (*x & AE_F)
@@ -63,8 +74,11 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
63#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) 74#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21)
64#define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); 75#define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x));
65 76
66#define PERR_IE_DST_ADDR(x) (x + 2) 77#define PERR_IE_TTL(x) (*(x))
67#define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); 78#define PERR_IE_DST_FLAGS(x) (*(x + 2))
79#define PERR_IE_DST_ADDR(x) (x + 3)
80#define PERR_IE_DST_DSN(x) u32_field_get(x, 9, 0);
81#define PERR_IE_DST_RCODE(x) u16_field_get(x, 13, 0);
68 82
69#define MSEC_TO_TU(x) (x*1000/1024) 83#define MSEC_TO_TU(x) (x*1000/1024)
70#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) 84#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0)
@@ -181,8 +195,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
181 * @dst_dsn: dsn of the broken destination 195 * @dst_dsn: dsn of the broken destination
182 * @ra: node this frame is addressed to 196 * @ra: node this frame is addressed to
183 */ 197 */
184int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, 198int mesh_path_error_tx(u8 ttl, u8 *dst, __le32 dst_dsn, __le16 dst_rcode,
185 struct ieee80211_sub_if_data *sdata) 199 u8 *ra, struct ieee80211_sub_if_data *sdata)
186{ 200{
187 struct ieee80211_local *local = sdata->local; 201 struct ieee80211_local *local = sdata->local;
188 struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); 202 struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
@@ -207,17 +221,29 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra,
207 /* BSSID is left zeroed, wildcard value */ 221 /* BSSID is left zeroed, wildcard value */
208 mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; 222 mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
209 mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; 223 mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
210 ie_len = 12; 224 ie_len = 15;
211 pos = skb_put(skb, 2 + ie_len); 225 pos = skb_put(skb, 2 + ie_len);
212 *pos++ = WLAN_EID_PERR; 226 *pos++ = WLAN_EID_PERR;
213 *pos++ = ie_len; 227 *pos++ = ie_len;
214 /* mode flags, reserved */ 228 /* ttl */
215 *pos++ = 0; 229 *pos++ = MESH_TTL;
216 /* number of destinations */ 230 /* number of destinations */
217 *pos++ = 1; 231 *pos++ = 1;
232 /*
233 * flags bit, bit 1 is unset if we know the sequence number and
234 * bit 2 is set if we have a reason code
235 */
236 *pos = 0;
237 if (!dst_dsn)
238 *pos |= MP_F_USN;
239 if (dst_rcode)
240 *pos |= MP_F_RCODE;
241 pos++;
218 memcpy(pos, dst, ETH_ALEN); 242 memcpy(pos, dst, ETH_ALEN);
219 pos += ETH_ALEN; 243 pos += ETH_ALEN;
220 memcpy(pos, &dst_dsn, 4); 244 memcpy(pos, &dst_dsn, 4);
245 pos += 4;
246 memcpy(pos, &dst_rcode, 2);
221 247
222 ieee80211_tx_skb(sdata, skb, 1); 248 ieee80211_tx_skb(sdata, skb, 1);
223 return 0; 249 return 0;
@@ -598,13 +624,26 @@ fail:
598static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, 624static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
599 struct ieee80211_mgmt *mgmt, u8 *perr_elem) 625 struct ieee80211_mgmt *mgmt, u8 *perr_elem)
600{ 626{
627 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
601 struct mesh_path *mpath; 628 struct mesh_path *mpath;
629 u8 ttl;
602 u8 *ta, *dst_addr; 630 u8 *ta, *dst_addr;
631 u8 dst_flags;
603 u32 dst_dsn; 632 u32 dst_dsn;
633 u16 dst_rcode;
604 634
605 ta = mgmt->sa; 635 ta = mgmt->sa;
636 ttl = PERR_IE_TTL(perr_elem);
637 if (ttl <= 1) {
638 ifmsh->mshstats.dropped_frames_ttl++;
639 return;
640 }
641 ttl--;
642 dst_flags = PERR_IE_DST_FLAGS(perr_elem);
606 dst_addr = PERR_IE_DST_ADDR(perr_elem); 643 dst_addr = PERR_IE_DST_ADDR(perr_elem);
607 dst_dsn = PERR_IE_DST_DSN(perr_elem); 644 dst_dsn = PERR_IE_DST_DSN(perr_elem);
645 dst_rcode = PERR_IE_DST_RCODE(perr_elem);
646
608 rcu_read_lock(); 647 rcu_read_lock();
609 mpath = mesh_path_lookup(dst_addr, sdata); 648 mpath = mesh_path_lookup(dst_addr, sdata);
610 if (mpath) { 649 if (mpath) {
@@ -616,7 +655,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
616 mpath->flags &= ~MESH_PATH_ACTIVE; 655 mpath->flags &= ~MESH_PATH_ACTIVE;
617 mpath->dsn = dst_dsn; 656 mpath->dsn = dst_dsn;
618 spin_unlock_bh(&mpath->state_lock); 657 spin_unlock_bh(&mpath->state_lock);
619 mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), 658 mesh_path_error_tx(ttl, dst_addr, cpu_to_le32(dst_dsn),
659 cpu_to_le16(dst_rcode),
620 sdata->dev->broadcast, sdata); 660 sdata->dev->broadcast, sdata);
621 } else 661 } else
622 spin_unlock_bh(&mpath->state_lock); 662 spin_unlock_bh(&mpath->state_lock);
@@ -711,7 +751,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
711 last_hop_metric); 751 last_hop_metric);
712 } 752 }
713 if (elems.perr) { 753 if (elems.perr) {
714 if (elems.perr_len != 12) 754 if (elems.perr_len != 15)
715 /* Right now we support only one destination per PERR */ 755 /* Right now we support only one destination per PERR */
716 return; 756 return;
717 hwmp_perr_frame_process(sdata, mgmt, elems.perr); 757 hwmp_perr_frame_process(sdata, mgmt, elems.perr);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 751c4d0e2b36..5d541235ca2f 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -465,8 +465,9 @@ void mesh_plink_broken(struct sta_info *sta)
465 mpath->flags &= ~MESH_PATH_ACTIVE; 465 mpath->flags &= ~MESH_PATH_ACTIVE;
466 ++mpath->dsn; 466 ++mpath->dsn;
467 spin_unlock_bh(&mpath->state_lock); 467 spin_unlock_bh(&mpath->state_lock);
468 mesh_path_error_tx(mpath->dst, 468 mesh_path_error_tx(MESH_TTL, mpath->dst,
469 cpu_to_le32(mpath->dsn), 469 cpu_to_le32(mpath->dsn),
470 PERR_RCODE_DEST_UNREACH,
470 sdata->dev->broadcast, sdata); 471 sdata->dev->broadcast, sdata);
471 } else 472 } else
472 spin_unlock_bh(&mpath->state_lock); 473 spin_unlock_bh(&mpath->state_lock);
@@ -611,7 +612,8 @@ void mesh_path_discard_frame(struct sk_buff *skb,
611 mpath = mesh_path_lookup(da, sdata); 612 mpath = mesh_path_lookup(da, sdata);
612 if (mpath) 613 if (mpath)
613 dsn = ++mpath->dsn; 614 dsn = ++mpath->dsn;
614 mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, sdata); 615 mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(dsn),
616 PERR_RCODE_NO_ROUTE, ra, sdata);
615 } 617 }
616 618
617 kfree_skb(skb); 619 kfree_skb(skb);