diff options
Diffstat (limited to 'net/wireless/mesh.c')
-rw-r--r-- | net/wireless/mesh.c | 121 |
1 files changed, 118 insertions, 3 deletions
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 2749cb86b462..c384e77ff77a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -14,6 +14,9 @@ | |||
14 | 14 | ||
15 | #define MESH_PATH_TIMEOUT 5000 | 15 | #define MESH_PATH_TIMEOUT 5000 |
16 | #define MESH_RANN_INTERVAL 5000 | 16 | #define MESH_RANN_INTERVAL 5000 |
17 | #define MESH_PATH_TO_ROOT_TIMEOUT 6000 | ||
18 | #define MESH_ROOT_INTERVAL 5000 | ||
19 | #define MESH_ROOT_CONFIRMATION_INTERVAL 2000 | ||
17 | 20 | ||
18 | /* | 21 | /* |
19 | * Minimum interval between two consecutive PREQs originated by the same | 22 | * Minimum interval between two consecutive PREQs originated by the same |
@@ -62,9 +65,15 @@ const struct mesh_config default_mesh_config = { | |||
62 | .dot11MeshForwarding = true, | 65 | .dot11MeshForwarding = true, |
63 | .rssi_threshold = MESH_RSSI_THRESHOLD, | 66 | .rssi_threshold = MESH_RSSI_THRESHOLD, |
64 | .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, | 67 | .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, |
68 | .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT, | ||
69 | .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL, | ||
70 | .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, | ||
65 | }; | 71 | }; |
66 | 72 | ||
67 | const struct mesh_setup default_mesh_setup = { | 73 | const struct mesh_setup default_mesh_setup = { |
74 | /* cfg80211_join_mesh() will pick a channel if needed */ | ||
75 | .channel = NULL, | ||
76 | .channel_type = NL80211_CHAN_NO_HT, | ||
68 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, | 77 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, |
69 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, | 78 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, |
70 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, | 79 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, |
@@ -75,7 +84,7 @@ const struct mesh_setup default_mesh_setup = { | |||
75 | 84 | ||
76 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 85 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
77 | struct net_device *dev, | 86 | struct net_device *dev, |
78 | const struct mesh_setup *setup, | 87 | struct mesh_setup *setup, |
79 | const struct mesh_config *conf) | 88 | const struct mesh_config *conf) |
80 | { | 89 | { |
81 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 90 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -101,10 +110,61 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
101 | if (!rdev->ops->join_mesh) | 110 | if (!rdev->ops->join_mesh) |
102 | return -EOPNOTSUPP; | 111 | return -EOPNOTSUPP; |
103 | 112 | ||
113 | if (!setup->channel) { | ||
114 | /* if no channel explicitly given, use preset channel */ | ||
115 | setup->channel = wdev->preset_chan; | ||
116 | setup->channel_type = wdev->preset_chantype; | ||
117 | } | ||
118 | |||
119 | if (!setup->channel) { | ||
120 | /* if we don't have that either, use the first usable channel */ | ||
121 | enum ieee80211_band band; | ||
122 | |||
123 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
124 | struct ieee80211_supported_band *sband; | ||
125 | struct ieee80211_channel *chan; | ||
126 | int i; | ||
127 | |||
128 | sband = rdev->wiphy.bands[band]; | ||
129 | if (!sband) | ||
130 | continue; | ||
131 | |||
132 | for (i = 0; i < sband->n_channels; i++) { | ||
133 | chan = &sband->channels[i]; | ||
134 | if (chan->flags & (IEEE80211_CHAN_NO_IBSS | | ||
135 | IEEE80211_CHAN_PASSIVE_SCAN | | ||
136 | IEEE80211_CHAN_DISABLED | | ||
137 | IEEE80211_CHAN_RADAR)) | ||
138 | continue; | ||
139 | setup->channel = chan; | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | if (setup->channel) | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | /* no usable channel ... */ | ||
148 | if (!setup->channel) | ||
149 | return -EINVAL; | ||
150 | |||
151 | setup->channel_type = NL80211_CHAN_NO_HT; | ||
152 | } | ||
153 | |||
154 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel, | ||
155 | setup->channel_type)) | ||
156 | return -EINVAL; | ||
157 | |||
158 | err = cfg80211_can_use_chan(rdev, wdev, setup->channel, | ||
159 | CHAN_MODE_SHARED); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
104 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); | 163 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); |
105 | if (!err) { | 164 | if (!err) { |
106 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 165 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
107 | wdev->mesh_id_len = setup->mesh_id_len; | 166 | wdev->mesh_id_len = setup->mesh_id_len; |
167 | wdev->channel = setup->channel; | ||
108 | } | 168 | } |
109 | 169 | ||
110 | return err; | 170 | return err; |
@@ -112,19 +172,71 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
112 | 172 | ||
113 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 173 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, |
114 | struct net_device *dev, | 174 | struct net_device *dev, |
115 | const struct mesh_setup *setup, | 175 | struct mesh_setup *setup, |
116 | const struct mesh_config *conf) | 176 | const struct mesh_config *conf) |
117 | { | 177 | { |
118 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 178 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
119 | int err; | 179 | int err; |
120 | 180 | ||
181 | mutex_lock(&rdev->devlist_mtx); | ||
121 | wdev_lock(wdev); | 182 | wdev_lock(wdev); |
122 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | 183 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
123 | wdev_unlock(wdev); | 184 | wdev_unlock(wdev); |
185 | mutex_unlock(&rdev->devlist_mtx); | ||
124 | 186 | ||
125 | return err; | 187 | return err; |
126 | } | 188 | } |
127 | 189 | ||
190 | int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | ||
191 | struct wireless_dev *wdev, int freq, | ||
192 | enum nl80211_channel_type channel_type) | ||
193 | { | ||
194 | struct ieee80211_channel *channel; | ||
195 | int err; | ||
196 | |||
197 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
198 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
199 | channel, | ||
200 | channel_type)) { | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * Workaround for libertas (only!), it puts the interface | ||
206 | * into mesh mode but doesn't implement join_mesh. Instead, | ||
207 | * it is configured via sysfs and then joins the mesh when | ||
208 | * you set the channel. Note that the libertas mesh isn't | ||
209 | * compatible with 802.11 mesh. | ||
210 | */ | ||
211 | if (rdev->ops->libertas_set_mesh_channel) { | ||
212 | if (channel_type != NL80211_CHAN_NO_HT) | ||
213 | return -EINVAL; | ||
214 | |||
215 | if (!netif_running(wdev->netdev)) | ||
216 | return -ENETDOWN; | ||
217 | |||
218 | err = cfg80211_can_use_chan(rdev, wdev, channel, | ||
219 | CHAN_MODE_SHARED); | ||
220 | if (err) | ||
221 | return err; | ||
222 | |||
223 | err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | ||
224 | wdev->netdev, | ||
225 | channel); | ||
226 | if (!err) | ||
227 | wdev->channel = channel; | ||
228 | |||
229 | return err; | ||
230 | } | ||
231 | |||
232 | if (wdev->mesh_id_len) | ||
233 | return -EBUSY; | ||
234 | |||
235 | wdev->preset_chan = channel; | ||
236 | wdev->preset_chantype = channel_type; | ||
237 | return 0; | ||
238 | } | ||
239 | |||
128 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, | 240 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, |
129 | const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) | 241 | const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) |
130 | { | 242 | { |
@@ -156,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
156 | return -ENOTCONN; | 268 | return -ENOTCONN; |
157 | 269 | ||
158 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | 270 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); |
159 | if (!err) | 271 | if (!err) { |
160 | wdev->mesh_id_len = 0; | 272 | wdev->mesh_id_len = 0; |
273 | wdev->channel = NULL; | ||
274 | } | ||
275 | |||
161 | return err; | 276 | return err; |
162 | } | 277 | } |
163 | 278 | ||