Commit 082ebb0c258d28af7452b19df9ef8b7553f37690

Authored by Thomas Pedersen
Committed by John W. Linville
1 parent f6a3e99da8

mac80211: fix mesh beacon format

Correct ordering of IEs in the mesh beacon while removing unneeded IEs
from mesh peering frames. Set privacy bit in capability info if security
is enabled. Add utility functions to aid in construction
of IEs and reduce code duplication.

Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

Showing 4 changed files with 196 additions and 62 deletions Side-by-side Diff

... ... @@ -204,36 +204,185 @@
204 204 return 0;
205 205 }
206 206  
207   -void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
  207 +int
  208 +mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
208 209 {
  210 + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  211 + u8 *pos, neighbors;
  212 + u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
  213 +
  214 + if (skb_tailroom(skb) < 2 + meshconf_len)
  215 + return -ENOMEM;
  216 +
  217 + pos = skb_put(skb, 2 + meshconf_len);
  218 + *pos++ = WLAN_EID_MESH_CONFIG;
  219 + *pos++ = meshconf_len;
  220 +
  221 + /* Active path selection protocol ID */
  222 + *pos++ = ifmsh->mesh_pp_id;
  223 + /* Active path selection metric ID */
  224 + *pos++ = ifmsh->mesh_pm_id;
  225 + /* Congestion control mode identifier */
  226 + *pos++ = ifmsh->mesh_cc_id;
  227 + /* Synchronization protocol identifier */
  228 + *pos++ = ifmsh->mesh_sp_id;
  229 + /* Authentication Protocol identifier */
  230 + *pos++ = ifmsh->mesh_auth_id;
  231 + /* Mesh Formation Info - number of neighbors */
  232 + neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
  233 + /* Number of neighbor mesh STAs or 15 whichever is smaller */
  234 + neighbors = (neighbors > 15) ? 15 : neighbors;
  235 + *pos++ = neighbors << 1;
  236 + /* Mesh capability */
  237 + ifmsh->accepting_plinks = mesh_plink_availables(sdata);
  238 + *pos = MESHCONF_CAPAB_FORWARDING;
  239 + *pos++ |= ifmsh->accepting_plinks ?
  240 + MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
  241 + *pos++ = 0x00;
  242 +
  243 + return 0;
  244 +}
  245 +
  246 +int
  247 +mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
  248 +{
  249 + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  250 + u8 *pos;
  251 +
  252 + if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
  253 + return -ENOMEM;
  254 +
  255 + pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
  256 + *pos++ = WLAN_EID_MESH_ID;
  257 + *pos++ = ifmsh->mesh_id_len;
  258 + if (ifmsh->mesh_id_len)
  259 + memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
  260 +
  261 + return 0;
  262 +}
  263 +
  264 +int
  265 +mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
  266 +{
  267 + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  268 + u8 offset, len;
  269 + const u8 *data;
  270 +
  271 + if (!ifmsh->ie || !ifmsh->ie_len)
  272 + return 0;
  273 +
  274 + /* fast-forward to vendor IEs */
  275 + offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
  276 +
  277 + if (offset) {
  278 + len = ifmsh->ie_len - offset;
  279 + data = ifmsh->ie + offset;
  280 + if (skb_tailroom(skb) < len)
  281 + return -ENOMEM;
  282 + memcpy(skb_put(skb, len), data, len);
  283 + }
  284 +
  285 + return 0;
  286 +}
  287 +
  288 +int
  289 +mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
  290 +{
  291 + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  292 + u8 len = 0;
  293 + const u8 *data;
  294 +
  295 + if (!ifmsh->ie || !ifmsh->ie_len)
  296 + return 0;
  297 +
  298 + /* find RSN IE */
  299 + data = ifmsh->ie;
  300 + while (data < ifmsh->ie + ifmsh->ie_len) {
  301 + if (*data == WLAN_EID_RSN) {
  302 + len = data[1] + 2;
  303 + break;
  304 + }
  305 + data++;
  306 + }
  307 +
  308 + if (len) {
  309 + if (skb_tailroom(skb) < len)
  310 + return -ENOMEM;
  311 + memcpy(skb_put(skb, len), data, len);
  312 + }
  313 +
  314 + return 0;
  315 +}
  316 +
  317 +int
  318 +mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
  319 +{
209 320 struct ieee80211_local *local = sdata->local;
210 321 struct ieee80211_supported_band *sband;
211   - u8 *pos;
212   - int len, i, rate;
213   - u8 neighbors;
  322 + int rate;
  323 + u8 i, rates, *pos;
214 324  
215 325 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
216   - len = sband->n_bitrates;
217   - if (len > 8)
218   - len = 8;
219   - pos = skb_put(skb, len + 2);
  326 + rates = sband->n_bitrates;
  327 + if (rates > 8)
  328 + rates = 8;
  329 +
  330 + if (skb_tailroom(skb) < rates + 2)
  331 + return -ENOMEM;
  332 +
  333 + pos = skb_put(skb, rates + 2);
220 334 *pos++ = WLAN_EID_SUPP_RATES;
221   - *pos++ = len;
222   - for (i = 0; i < len; i++) {
  335 + *pos++ = rates;
  336 + for (i = 0; i < rates; i++) {
223 337 rate = sband->bitrates[i].bitrate;
224 338 *pos++ = (u8) (rate / 5);
225 339 }
226 340  
227   - if (sband->n_bitrates > len) {
228   - pos = skb_put(skb, sband->n_bitrates - len + 2);
  341 + return 0;
  342 +}
  343 +
  344 +int
  345 +mesh_add_ext_srates_ie(struct sk_buff *skb,
  346 + struct ieee80211_sub_if_data *sdata)
  347 +{
  348 + struct ieee80211_local *local = sdata->local;
  349 + struct ieee80211_supported_band *sband;
  350 + int rate;
  351 + u8 i, exrates, *pos;
  352 +
  353 + sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  354 + exrates = sband->n_bitrates;
  355 + if (exrates > 8)
  356 + exrates -= 8;
  357 + else
  358 + exrates = 0;
  359 +
  360 + if (skb_tailroom(skb) < exrates + 2)
  361 + return -ENOMEM;
  362 +
  363 + if (exrates) {
  364 + pos = skb_put(skb, exrates + 2);
229 365 *pos++ = WLAN_EID_EXT_SUPP_RATES;
230   - *pos++ = sband->n_bitrates - len;
231   - for (i = len; i < sband->n_bitrates; i++) {
  366 + *pos++ = exrates;
  367 + for (i = 8; i < sband->n_bitrates; i++) {
232 368 rate = sband->bitrates[i].bitrate;
233 369 *pos++ = (u8) (rate / 5);
234 370 }
235 371 }
  372 + return 0;
  373 +}
236 374  
  375 +int mesh_add_ds_params_ie(struct sk_buff *skb,
  376 + struct ieee80211_sub_if_data *sdata)
  377 +{
  378 + struct ieee80211_local *local = sdata->local;
  379 + struct ieee80211_supported_band *sband;
  380 + u8 *pos;
  381 +
  382 + if (skb_tailroom(skb) < 3)
  383 + return -ENOMEM;
  384 +
  385 + sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
237 386 if (sband->band == IEEE80211_BAND_2GHZ) {
238 387 pos = skb_put(skb, 2 + 1);
239 388 *pos++ = WLAN_EID_DS_PARAMS;
240 389  
... ... @@ -241,52 +390,8 @@
241 390 *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
242 391 }
243 392  
244   - pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len);
245   - *pos++ = WLAN_EID_MESH_ID;
246   - *pos++ = sdata->u.mesh.mesh_id_len;
247   - if (sdata->u.mesh.mesh_id_len)
248   - memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
249   -
250   - pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie));
251   - *pos++ = WLAN_EID_MESH_CONFIG;
252   - *pos++ = sizeof(struct ieee80211_meshconf_ie);
253   -
254   - /* Active path selection protocol ID */
255   - *pos++ = sdata->u.mesh.mesh_pp_id;
256   -
257   - /* Active path selection metric ID */
258   - *pos++ = sdata->u.mesh.mesh_pm_id;
259   -
260   - /* Congestion control mode identifier */
261   - *pos++ = sdata->u.mesh.mesh_cc_id;
262   -
263   - /* Synchronization protocol identifier */
264   - *pos++ = sdata->u.mesh.mesh_sp_id;
265   -
266   - /* Authentication Protocol identifier */
267   - *pos++ = sdata->u.mesh.mesh_auth_id;
268   -
269   - /* Mesh Formation Info - number of neighbors */
270   - neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
271   - /* Number of neighbor mesh STAs or 15 whichever is smaller */
272   - neighbors = (neighbors > 15) ? 15 : neighbors;
273   - *pos++ = neighbors << 1;
274   -
275   - /* Mesh capability */
276   - sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
277   - *pos = MESHCONF_CAPAB_FORWARDING;
278   - *pos++ |= sdata->u.mesh.accepting_plinks ?
279   - MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
280   - *pos++ = 0x00;
281   -
282   - if (sdata->u.mesh.ie) {
283   - int len = sdata->u.mesh.ie_len;
284   - const u8 *data = sdata->u.mesh.ie;
285   - if (skb_tailroom(skb) > len)
286   - memcpy(skb_put(skb, len), data, len);
287   - }
  393 + return 0;
288 394 }
289   -
290 395  
291 396 static void ieee80211_mesh_path_timer(unsigned long data)
292 397 {
... ... @@ -199,6 +199,20 @@
199 199 void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
200 200 void mesh_mgmt_ies_add(struct sk_buff *skb,
201 201 struct ieee80211_sub_if_data *sdata);
  202 +int mesh_add_meshconf_ie(struct sk_buff *skb,
  203 + struct ieee80211_sub_if_data *sdata);
  204 +int mesh_add_meshid_ie(struct sk_buff *skb,
  205 + struct ieee80211_sub_if_data *sdata);
  206 +int mesh_add_rsn_ie(struct sk_buff *skb,
  207 + struct ieee80211_sub_if_data *sdata);
  208 +int mesh_add_vendor_ies(struct sk_buff *skb,
  209 + struct ieee80211_sub_if_data *sdata);
  210 +int mesh_add_srates_ie(struct sk_buff *skb,
  211 + struct ieee80211_sub_if_data *sdata);
  212 +int mesh_add_ext_srates_ie(struct sk_buff *skb,
  213 + struct ieee80211_sub_if_data *sdata);
  214 +int mesh_add_ds_params_ie(struct sk_buff *skb,
  215 + struct ieee80211_sub_if_data *sdata);
202 216 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
203 217 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
204 218 void ieee80211s_init(void);
net/mac80211/mesh_plink.c
... ... @@ -195,7 +195,12 @@
195 195 memset(pos, 0, 2);
196 196 memcpy(pos + 2, &plid, 2);
197 197 }
198   - mesh_mgmt_ies_add(skb, sdata);
  198 + if (mesh_add_srates_ie(skb, sdata) ||
  199 + mesh_add_ext_srates_ie(skb, sdata) ||
  200 + mesh_add_rsn_ie(skb, sdata) ||
  201 + mesh_add_meshid_ie(skb, sdata) ||
  202 + mesh_add_meshconf_ie(skb, sdata))
  203 + return -1;
199 204 }
200 205  
201 206 /* Add Peer Link Management element */
... ... @@ -2295,13 +2295,23 @@
2295 2295 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
2296 2296 mgmt->u.beacon.beacon_int =
2297 2297 cpu_to_le16(sdata->vif.bss_conf.beacon_int);
2298   - mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
  2298 + mgmt->u.beacon.capab_info |= cpu_to_le16(
  2299 + sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
2299 2300  
2300 2301 pos = skb_put(skb, 2);
2301 2302 *pos++ = WLAN_EID_SSID;
2302 2303 *pos++ = 0x0;
2303 2304  
2304   - mesh_mgmt_ies_add(skb, sdata);
  2305 + if (mesh_add_srates_ie(skb, sdata) ||
  2306 + mesh_add_ds_params_ie(skb, sdata) ||
  2307 + mesh_add_ext_srates_ie(skb, sdata) ||
  2308 + mesh_add_rsn_ie(skb, sdata) ||
  2309 + mesh_add_meshid_ie(skb, sdata) ||
  2310 + mesh_add_meshconf_ie(skb, sdata) ||
  2311 + mesh_add_vendor_ies(skb, sdata)) {
  2312 + pr_err("o11s: couldn't add ies!\n");
  2313 + goto out;
  2314 + }
2305 2315 } else {
2306 2316 WARN_ON(1);
2307 2317 goto out;