diff options
Diffstat (limited to 'net/mac80211/mesh.c')
| -rw-r--r-- | net/mac80211/mesh.c | 259 |
1 files changed, 190 insertions, 69 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 29e9980c8e60..28ab510e621a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -13,10 +13,6 @@ | |||
| 13 | #include "ieee80211_i.h" | 13 | #include "ieee80211_i.h" |
| 14 | #include "mesh.h" | 14 | #include "mesh.h" |
| 15 | 15 | ||
| 16 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | ||
| 17 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | ||
| 18 | #define IEEE80211_MESH_RANN_INTERVAL (1 * HZ) | ||
| 19 | |||
| 20 | #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 | 16 | #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 |
| 21 | #define MESHCONF_CAPAB_FORWARDING 0x08 | 17 | #define MESHCONF_CAPAB_FORWARDING 0x08 |
| 22 | 18 | ||
| @@ -27,6 +23,17 @@ | |||
| 27 | int mesh_allocated; | 23 | int mesh_allocated; |
| 28 | static struct kmem_cache *rm_cache; | 24 | static struct kmem_cache *rm_cache; |
| 29 | 25 | ||
| 26 | #ifdef CONFIG_MAC80211_MESH | ||
| 27 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt) | ||
| 28 | { | ||
| 29 | return (mgmt->u.action.u.mesh_action.action_code == | ||
| 30 | WLAN_MESH_ACTION_HWMP_PATH_SELECTION); | ||
| 31 | } | ||
| 32 | #else | ||
| 33 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt) | ||
| 34 | { return false; } | ||
| 35 | #endif | ||
| 36 | |||
| 30 | void ieee80211s_init(void) | 37 | void ieee80211s_init(void) |
| 31 | { | 38 | { |
| 32 | mesh_pathtbl_init(); | 39 | mesh_pathtbl_init(); |
| @@ -204,36 +211,185 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | |||
| 204 | return 0; | 211 | return 0; |
| 205 | } | 212 | } |
| 206 | 213 | ||
| 207 | void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | 214 | int |
| 215 | mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | ||
| 216 | { | ||
| 217 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
| 218 | u8 *pos, neighbors; | ||
| 219 | u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie); | ||
| 220 | |||
| 221 | if (skb_tailroom(skb) < 2 + meshconf_len) | ||
| 222 | return -ENOMEM; | ||
| 223 | |||
| 224 | pos = skb_put(skb, 2 + meshconf_len); | ||
| 225 | *pos++ = WLAN_EID_MESH_CONFIG; | ||
| 226 | *pos++ = meshconf_len; | ||
| 227 | |||
| 228 | /* Active path selection protocol ID */ | ||
| 229 | *pos++ = ifmsh->mesh_pp_id; | ||
| 230 | /* Active path selection metric ID */ | ||
| 231 | *pos++ = ifmsh->mesh_pm_id; | ||
| 232 | /* Congestion control mode identifier */ | ||
| 233 | *pos++ = ifmsh->mesh_cc_id; | ||
| 234 | /* Synchronization protocol identifier */ | ||
| 235 | *pos++ = ifmsh->mesh_sp_id; | ||
| 236 | /* Authentication Protocol identifier */ | ||
| 237 | *pos++ = ifmsh->mesh_auth_id; | ||
| 238 | /* Mesh Formation Info - number of neighbors */ | ||
| 239 | neighbors = atomic_read(&ifmsh->mshstats.estab_plinks); | ||
| 240 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ | ||
| 241 | neighbors = (neighbors > 15) ? 15 : neighbors; | ||
| 242 | *pos++ = neighbors << 1; | ||
| 243 | /* Mesh capability */ | ||
| 244 | ifmsh->accepting_plinks = mesh_plink_availables(sdata); | ||
| 245 | *pos = MESHCONF_CAPAB_FORWARDING; | ||
| 246 | *pos++ |= ifmsh->accepting_plinks ? | ||
| 247 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | ||
| 248 | *pos++ = 0x00; | ||
| 249 | |||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | int | ||
| 254 | mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | ||
| 255 | { | ||
| 256 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
| 257 | u8 *pos; | ||
| 258 | |||
| 259 | if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len) | ||
| 260 | return -ENOMEM; | ||
| 261 | |||
| 262 | pos = skb_put(skb, 2 + ifmsh->mesh_id_len); | ||
| 263 | *pos++ = WLAN_EID_MESH_ID; | ||
| 264 | *pos++ = ifmsh->mesh_id_len; | ||
| 265 | if (ifmsh->mesh_id_len) | ||
| 266 | memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len); | ||
| 267 | |||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | int | ||
| 272 | mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | ||
| 273 | { | ||
| 274 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
| 275 | u8 offset, len; | ||
| 276 | const u8 *data; | ||
| 277 | |||
| 278 | if (!ifmsh->ie || !ifmsh->ie_len) | ||
| 279 | return 0; | ||
| 280 | |||
| 281 | /* fast-forward to vendor IEs */ | ||
| 282 | offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0); | ||
| 283 | |||
| 284 | if (offset) { | ||
| 285 | len = ifmsh->ie_len - offset; | ||
| 286 | data = ifmsh->ie + offset; | ||
| 287 | if (skb_tailroom(skb) < len) | ||
| 288 | return -ENOMEM; | ||
| 289 | memcpy(skb_put(skb, len), data, len); | ||
| 290 | } | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | int | ||
| 296 | mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | ||
| 297 | { | ||
| 298 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
| 299 | u8 len = 0; | ||
| 300 | const u8 *data; | ||
| 301 | |||
| 302 | if (!ifmsh->ie || !ifmsh->ie_len) | ||
| 303 | return 0; | ||
| 304 | |||
| 305 | /* find RSN IE */ | ||
| 306 | data = ifmsh->ie; | ||
| 307 | while (data < ifmsh->ie + ifmsh->ie_len) { | ||
| 308 | if (*data == WLAN_EID_RSN) { | ||
| 309 | len = data[1] + 2; | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | data++; | ||
| 313 | } | ||
| 314 | |||
| 315 | if (len) { | ||
| 316 | if (skb_tailroom(skb) < len) | ||
| 317 | return -ENOMEM; | ||
| 318 | memcpy(skb_put(skb, len), data, len); | ||
| 319 | } | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | int | ||
| 325 | mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | ||
| 208 | { | 326 | { |
| 209 | struct ieee80211_local *local = sdata->local; | 327 | struct ieee80211_local *local = sdata->local; |
| 210 | struct ieee80211_supported_band *sband; | 328 | struct ieee80211_supported_band *sband; |
| 211 | u8 *pos; | 329 | int rate; |
| 212 | int len, i, rate; | 330 | u8 i, rates, *pos; |
| 213 | u8 neighbors; | ||
| 214 | 331 | ||
| 215 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 332 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
| 216 | len = sband->n_bitrates; | 333 | rates = sband->n_bitrates; |
| 217 | if (len > 8) | 334 | if (rates > 8) |
| 218 | len = 8; | 335 | rates = 8; |
| 219 | pos = skb_put(skb, len + 2); | 336 | |
| 337 | if (skb_tailroom(skb) < rates + 2) | ||
| 338 | return -ENOMEM; | ||
| 339 | |||
| 340 | pos = skb_put(skb, rates + 2); | ||
| 220 | *pos++ = WLAN_EID_SUPP_RATES; | 341 | *pos++ = WLAN_EID_SUPP_RATES; |
| 221 | *pos++ = len; | 342 | *pos++ = rates; |
| 222 | for (i = 0; i < len; i++) { | 343 | for (i = 0; i < rates; i++) { |
| 223 | rate = sband->bitrates[i].bitrate; | 344 | rate = sband->bitrates[i].bitrate; |
| 224 | *pos++ = (u8) (rate / 5); | 345 | *pos++ = (u8) (rate / 5); |
| 225 | } | 346 | } |
| 226 | 347 | ||
| 227 | if (sband->n_bitrates > len) { | 348 | return 0; |
| 228 | pos = skb_put(skb, sband->n_bitrates - len + 2); | 349 | } |
| 350 | |||
| 351 | int | ||
| 352 | mesh_add_ext_srates_ie(struct sk_buff *skb, | ||
| 353 | struct ieee80211_sub_if_data *sdata) | ||
| 354 | { | ||
| 355 | struct ieee80211_local *local = sdata->local; | ||
| 356 | struct ieee80211_supported_band *sband; | ||
| 357 | int rate; | ||
| 358 | u8 i, exrates, *pos; | ||
| 359 | |||
| 360 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
| 361 | exrates = sband->n_bitrates; | ||
| 362 | if (exrates > 8) | ||
| 363 | exrates -= 8; | ||
| 364 | else | ||
| 365 | exrates = 0; | ||
| 366 | |||
| 367 | if (skb_tailroom(skb) < exrates + 2) | ||
| 368 | return -ENOMEM; | ||
| 369 | |||
| 370 | if (exrates) { | ||
| 371 | pos = skb_put(skb, exrates + 2); | ||
| 229 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 372 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
| 230 | *pos++ = sband->n_bitrates - len; | 373 | *pos++ = exrates; |
| 231 | for (i = len; i < sband->n_bitrates; i++) { | 374 | for (i = 8; i < sband->n_bitrates; i++) { |
| 232 | rate = sband->bitrates[i].bitrate; | 375 | rate = sband->bitrates[i].bitrate; |
| 233 | *pos++ = (u8) (rate / 5); | 376 | *pos++ = (u8) (rate / 5); |
| 234 | } | 377 | } |
| 235 | } | 378 | } |
| 379 | return 0; | ||
| 380 | } | ||
| 236 | 381 | ||
| 382 | int mesh_add_ds_params_ie(struct sk_buff *skb, | ||
| 383 | struct ieee80211_sub_if_data *sdata) | ||
| 384 | { | ||
| 385 | struct ieee80211_local *local = sdata->local; | ||
| 386 | struct ieee80211_supported_band *sband; | ||
| 387 | u8 *pos; | ||
| 388 | |||
| 389 | if (skb_tailroom(skb) < 3) | ||
| 390 | return -ENOMEM; | ||
| 391 | |||
| 392 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
| 237 | if (sband->band == IEEE80211_BAND_2GHZ) { | 393 | if (sband->band == IEEE80211_BAND_2GHZ) { |
| 238 | pos = skb_put(skb, 2 + 1); | 394 | pos = skb_put(skb, 2 + 1); |
| 239 | *pos++ = WLAN_EID_DS_PARAMS; | 395 | *pos++ = WLAN_EID_DS_PARAMS; |
| @@ -241,53 +397,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
| 241 | *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); | 397 | *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); |
| 242 | } | 398 | } |
| 243 | 399 | ||
| 244 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); | 400 | return 0; |
| 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 | } | ||
| 288 | } | 401 | } |
| 289 | 402 | ||
| 290 | |||
| 291 | static void ieee80211_mesh_path_timer(unsigned long data) | 403 | static void ieee80211_mesh_path_timer(unsigned long data) |
| 292 | { | 404 | { |
| 293 | struct ieee80211_sub_if_data *sdata = | 405 | struct ieee80211_sub_if_data *sdata = |
| @@ -425,7 +537,8 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) | |||
| 425 | 537 | ||
| 426 | mesh_path_tx_root_frame(sdata); | 538 | mesh_path_tx_root_frame(sdata); |
| 427 | mod_timer(&ifmsh->mesh_path_root_timer, | 539 | mod_timer(&ifmsh->mesh_path_root_timer, |
| 428 | round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); | 540 | round_jiffies(TU_TO_EXP_TIME( |
| 541 | ifmsh->mshcfg.dot11MeshHWMPRannInterval))); | ||
| 429 | } | 542 | } |
| 430 | 543 | ||
| 431 | #ifdef CONFIG_PM | 544 | #ifdef CONFIG_PM |
| @@ -433,7 +546,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | |||
| 433 | { | 546 | { |
| 434 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 547 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 435 | 548 | ||
| 436 | /* use atomic bitops in case both timers fire at the same time */ | 549 | /* use atomic bitops in case all timers fire at the same time */ |
| 437 | 550 | ||
| 438 | if (del_timer_sync(&ifmsh->housekeeping_timer)) | 551 | if (del_timer_sync(&ifmsh->housekeeping_timer)) |
| 439 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 552 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
| @@ -557,11 +670,18 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
| 557 | struct ieee80211_rx_status *rx_status) | 670 | struct ieee80211_rx_status *rx_status) |
| 558 | { | 671 | { |
| 559 | switch (mgmt->u.action.category) { | 672 | switch (mgmt->u.action.category) { |
| 560 | case WLAN_CATEGORY_MESH_ACTION: | 673 | case WLAN_CATEGORY_SELF_PROTECTED: |
| 561 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 674 | switch (mgmt->u.action.u.self_prot.action_code) { |
| 675 | case WLAN_SP_MESH_PEERING_OPEN: | ||
| 676 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
| 677 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
| 678 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | ||
| 679 | break; | ||
| 680 | } | ||
| 562 | break; | 681 | break; |
| 563 | case WLAN_CATEGORY_MESH_PATH_SEL: | 682 | case WLAN_CATEGORY_MESH_ACTION: |
| 564 | mesh_rx_path_sel_frame(sdata, mgmt, len); | 683 | if (mesh_action_is_path_sel(mgmt)) |
| 684 | mesh_rx_path_sel_frame(sdata, mgmt, len); | ||
| 565 | break; | 685 | break; |
| 566 | } | 686 | } |
| 567 | } | 687 | } |
| @@ -633,6 +753,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
| 633 | ifmsh->accepting_plinks = true; | 753 | ifmsh->accepting_plinks = true; |
| 634 | ifmsh->preq_id = 0; | 754 | ifmsh->preq_id = 0; |
| 635 | ifmsh->sn = 0; | 755 | ifmsh->sn = 0; |
| 756 | ifmsh->num_gates = 0; | ||
| 636 | atomic_set(&ifmsh->mpaths, 0); | 757 | atomic_set(&ifmsh->mpaths, 0); |
| 637 | mesh_rmc_init(sdata); | 758 | mesh_rmc_init(sdata); |
| 638 | ifmsh->last_preq = jiffies; | 759 | ifmsh->last_preq = jiffies; |
