diff options
-rw-r--r-- | include/linux/ieee80211.h | 15 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 79 | ||||
-rw-r--r-- | net/mac80211/util.c | 4 |
4 files changed, 91 insertions, 8 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 50c684db33c7..49b1abd2fe97 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -554,6 +554,20 @@ struct ieee80211_tim_ie { | |||
554 | u8 virtual_map[1]; | 554 | u8 virtual_map[1]; |
555 | } __attribute__ ((packed)); | 555 | } __attribute__ ((packed)); |
556 | 556 | ||
557 | /** | ||
558 | * struct ieee80211_rann_ie | ||
559 | * | ||
560 | * This structure refers to "Root Announcement information element" | ||
561 | */ | ||
562 | struct ieee80211_rann_ie { | ||
563 | u8 rann_flags; | ||
564 | u8 rann_hopcount; | ||
565 | u8 rann_ttl; | ||
566 | u8 rann_addr[6]; | ||
567 | u32 rann_seq; | ||
568 | u32 rann_metric; | ||
569 | } __attribute__ ((packed)); | ||
570 | |||
557 | #define WLAN_SA_QUERY_TR_ID_LEN 2 | 571 | #define WLAN_SA_QUERY_TR_ID_LEN 2 |
558 | 572 | ||
559 | struct ieee80211_mgmt { | 573 | struct ieee80211_mgmt { |
@@ -1070,6 +1084,7 @@ enum ieee80211_eid { | |||
1070 | WLAN_EID_PREQ = 68, | 1084 | WLAN_EID_PREQ = 68, |
1071 | WLAN_EID_PREP = 69, | 1085 | WLAN_EID_PREP = 69, |
1072 | WLAN_EID_PERR = 70, | 1086 | WLAN_EID_PERR = 70, |
1087 | WLAN_EID_RANN = 49, /* compatible with FreeBSD */ | ||
1073 | /* 802.11h */ | 1088 | /* 802.11h */ |
1074 | WLAN_EID_PWR_CONSTRAINT = 32, | 1089 | WLAN_EID_PWR_CONSTRAINT = 32, |
1075 | WLAN_EID_PWR_CAPABILITY = 33, | 1090 | WLAN_EID_PWR_CAPABILITY = 33, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 19b0c128d940..2a7d3d4067e1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -804,6 +804,7 @@ struct ieee802_11_elems { | |||
804 | u8 *preq; | 804 | u8 *preq; |
805 | u8 *prep; | 805 | u8 *prep; |
806 | u8 *perr; | 806 | u8 *perr; |
807 | struct ieee80211_rann_ie *rann; | ||
807 | u8 *ch_switch_elem; | 808 | u8 *ch_switch_elem; |
808 | u8 *country_elem; | 809 | u8 *country_elem; |
809 | u8 *pwr_constr_elem; | 810 | u8 *pwr_constr_elem; |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index db1a33098a88..7b9dd87cf9f2 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -28,6 +28,8 @@ | |||
28 | /* Reply and forward */ | 28 | /* Reply and forward */ |
29 | #define MP_F_RF 0x2 | 29 | #define MP_F_RF 0x2 |
30 | 30 | ||
31 | static void mesh_queue_preq(struct mesh_path *, u8); | ||
32 | |||
31 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | 33 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) |
32 | { | 34 | { |
33 | if (ae) | 35 | if (ae) |
@@ -81,7 +83,8 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
81 | enum mpath_frame_type { | 83 | enum mpath_frame_type { |
82 | MPATH_PREQ = 0, | 84 | MPATH_PREQ = 0, |
83 | MPATH_PREP, | 85 | MPATH_PREP, |
84 | MPATH_PERR | 86 | MPATH_PERR, |
87 | MPATH_RANN | ||
85 | }; | 88 | }; |
86 | 89 | ||
87 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 90 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
@@ -109,7 +112,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
109 | 112 | ||
110 | memcpy(mgmt->da, da, ETH_ALEN); | 113 | memcpy(mgmt->da, da, ETH_ALEN); |
111 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 114 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
112 | /* BSSID is left zeroed, wildcard value */ | 115 | /* BSSID == SA */ |
116 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
113 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 117 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
114 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; | 118 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
115 | 119 | ||
@@ -126,6 +130,12 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
126 | pos = skb_put(skb, 2 + ie_len); | 130 | pos = skb_put(skb, 2 + ie_len); |
127 | *pos++ = WLAN_EID_PREP; | 131 | *pos++ = WLAN_EID_PREP; |
128 | break; | 132 | break; |
133 | case MPATH_RANN: | ||
134 | mhwmp_dbg("sending RANN from %pM\n", orig_addr); | ||
135 | ie_len = sizeof(struct ieee80211_rann_ie); | ||
136 | pos = skb_put(skb, 2 + ie_len); | ||
137 | *pos++ = WLAN_EID_RANN; | ||
138 | break; | ||
129 | default: | 139 | default: |
130 | kfree_skb(skb); | 140 | kfree_skb(skb); |
131 | return -ENOTSUPP; | 141 | return -ENOTSUPP; |
@@ -143,8 +153,10 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
143 | pos += ETH_ALEN; | 153 | pos += ETH_ALEN; |
144 | memcpy(pos, &orig_dsn, 4); | 154 | memcpy(pos, &orig_dsn, 4); |
145 | pos += 4; | 155 | pos += 4; |
146 | memcpy(pos, &lifetime, 4); | 156 | if (action != MPATH_RANN) { |
147 | pos += 4; | 157 | memcpy(pos, &lifetime, 4); |
158 | pos += 4; | ||
159 | } | ||
148 | memcpy(pos, &metric, 4); | 160 | memcpy(pos, &metric, 4); |
149 | pos += 4; | 161 | pos += 4; |
150 | if (action == MPATH_PREQ) { | 162 | if (action == MPATH_PREQ) { |
@@ -152,9 +164,11 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
152 | *pos++ = 1; | 164 | *pos++ = 1; |
153 | *pos++ = dst_flags; | 165 | *pos++ = dst_flags; |
154 | } | 166 | } |
155 | memcpy(pos, dst, ETH_ALEN); | 167 | if (action != MPATH_RANN) { |
156 | pos += ETH_ALEN; | 168 | memcpy(pos, dst, ETH_ALEN); |
157 | memcpy(pos, &dst_dsn, 4); | 169 | pos += ETH_ALEN; |
170 | memcpy(pos, &dst_dsn, 4); | ||
171 | } | ||
158 | 172 | ||
159 | ieee80211_tx_skb(sdata, skb, 1); | 173 | ieee80211_tx_skb(sdata, skb, 1); |
160 | return 0; | 174 | return 0; |
@@ -610,6 +624,54 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
610 | rcu_read_unlock(); | 624 | rcu_read_unlock(); |
611 | } | 625 | } |
612 | 626 | ||
627 | static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | ||
628 | struct ieee80211_mgmt *mgmt, | ||
629 | struct ieee80211_rann_ie *rann) | ||
630 | { | ||
631 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
632 | struct mesh_path *mpath; | ||
633 | u8 *ta; | ||
634 | u8 ttl, flags, hopcount; | ||
635 | u8 *orig_addr; | ||
636 | u32 orig_dsn, metric; | ||
637 | |||
638 | ta = mgmt->sa; | ||
639 | ttl = rann->rann_ttl; | ||
640 | if (ttl <= 1) { | ||
641 | ifmsh->mshstats.dropped_frames_ttl++; | ||
642 | return; | ||
643 | } | ||
644 | ttl--; | ||
645 | flags = rann->rann_flags; | ||
646 | orig_addr = rann->rann_addr; | ||
647 | orig_dsn = rann->rann_seq; | ||
648 | hopcount = rann->rann_hopcount; | ||
649 | metric = rann->rann_metric; | ||
650 | mhwmp_dbg("received RANN from %pM\n", orig_addr); | ||
651 | |||
652 | rcu_read_lock(); | ||
653 | mpath = mesh_path_lookup(orig_addr, sdata); | ||
654 | if (!mpath) { | ||
655 | mesh_path_add(orig_addr, sdata); | ||
656 | mpath = mesh_path_lookup(orig_addr, sdata); | ||
657 | if (!mpath) { | ||
658 | rcu_read_unlock(); | ||
659 | sdata->u.mesh.mshstats.dropped_frames_no_route++; | ||
660 | return; | ||
661 | } | ||
662 | mesh_queue_preq(mpath, | ||
663 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | ||
664 | } | ||
665 | if (mpath->dsn < orig_dsn) { | ||
666 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, | ||
667 | cpu_to_le32(orig_dsn), | ||
668 | 0, NULL, 0, sdata->dev->broadcast, | ||
669 | hopcount, ttl, 0, cpu_to_le32(metric), | ||
670 | 0, sdata); | ||
671 | mpath->dsn = orig_dsn; | ||
672 | } | ||
673 | rcu_read_unlock(); | ||
674 | } | ||
613 | 675 | ||
614 | 676 | ||
615 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 677 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
@@ -654,7 +716,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |||
654 | return; | 716 | return; |
655 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); | 717 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); |
656 | } | 718 | } |
657 | 719 | if (elems.rann) | |
720 | hwmp_rann_frame_process(sdata, mgmt, elems.rann); | ||
658 | } | 721 | } |
659 | 722 | ||
660 | /** | 723 | /** |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aedbaaa067e6..da86e1592f8c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -685,6 +685,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
685 | elems->perr = pos; | 685 | elems->perr = pos; |
686 | elems->perr_len = elen; | 686 | elems->perr_len = elen; |
687 | break; | 687 | break; |
688 | case WLAN_EID_RANN: | ||
689 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
690 | elems->rann = (void *)pos; | ||
691 | break; | ||
688 | case WLAN_EID_CHANNEL_SWITCH: | 692 | case WLAN_EID_CHANNEL_SWITCH: |
689 | elems->ch_switch_elem = pos; | 693 | elems->ch_switch_elem = pos; |
690 | elems->ch_switch_elem_len = elen; | 694 | elems->ch_switch_elem_len = elen; |