diff options
-rw-r--r-- | net/mac80211/mesh.h | 9 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 58 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 6 |
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 */ |
215 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | 220 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, |
@@ -275,8 +280,8 @@ void mesh_mpp_table_grow(void); | |||
275 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 280 | u32 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 */ |
278 | int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, | 283 | int 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); |
280 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 285 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
281 | void mesh_path_flush_pending(struct mesh_path *mpath); | 286 | void mesh_path_flush_pending(struct mesh_path *mpath); |
282 | void mesh_path_tx_pending(struct mesh_path *mpath); | 287 | void 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 | ||
31 | static void mesh_queue_preq(struct mesh_path *, u8); | 35 | static 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 | ||
44 | static 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 | */ |
184 | int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | 198 | int 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: | |||
598 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | 624 | static 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); |