aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/mesh_plink.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 3323413acb77..e12be2e4e8df 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -422,20 +422,54 @@ out:
422 spin_unlock_bh(&sta->mesh->plink_lock); 422 spin_unlock_bh(&sta->mesh->plink_lock);
423} 423}
424 424
425static int mesh_allocate_aid(struct ieee80211_sub_if_data *sdata)
426{
427 struct sta_info *sta;
428 unsigned long *aid_map;
429 int aid;
430
431 aid_map = kcalloc(BITS_TO_LONGS(IEEE80211_MAX_AID + 1),
432 sizeof(*aid_map), GFP_KERNEL);
433 if (!aid_map)
434 return -ENOMEM;
435
436 /* reserve aid 0 for mcast indication */
437 __set_bit(0, aid_map);
438
439 rcu_read_lock();
440 list_for_each_entry_rcu(sta, &sdata->local->sta_list, list)
441 __set_bit(sta->sta.aid, aid_map);
442 rcu_read_unlock();
443
444 aid = find_first_zero_bit(aid_map, IEEE80211_MAX_AID + 1);
445 kfree(aid_map);
446
447 if (aid > IEEE80211_MAX_AID)
448 return -ENOBUFS;
449
450 return aid;
451}
452
425static struct sta_info * 453static struct sta_info *
426__mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) 454__mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
427{ 455{
428 struct sta_info *sta; 456 struct sta_info *sta;
457 int aid;
429 458
430 if (sdata->local->num_sta >= MESH_MAX_PLINKS) 459 if (sdata->local->num_sta >= MESH_MAX_PLINKS)
431 return NULL; 460 return NULL;
432 461
462 aid = mesh_allocate_aid(sdata);
463 if (aid < 0)
464 return NULL;
465
433 sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); 466 sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
434 if (!sta) 467 if (!sta)
435 return NULL; 468 return NULL;
436 469
437 sta->mesh->plink_state = NL80211_PLINK_LISTEN; 470 sta->mesh->plink_state = NL80211_PLINK_LISTEN;
438 sta->sta.wme = true; 471 sta->sta.wme = true;
472 sta->sta.aid = aid;
439 473
440 sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); 474 sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
441 sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); 475 sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
@@ -659,8 +693,6 @@ static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata)
659 693
660 do { 694 do {
661 get_random_bytes(&llid, sizeof(llid)); 695 get_random_bytes(&llid, sizeof(llid));
662 /* for mesh PS we still only have the AID range for TIM bits */
663 llid = (llid % IEEE80211_MAX_AID) + 1;
664 } while (llid_in_use(sdata, llid)); 696 } while (llid_in_use(sdata, llid));
665 697
666 return llid; 698 return llid;
@@ -1069,7 +1101,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
1069 goto unlock_rcu; 1101 goto unlock_rcu;
1070 } 1102 }
1071 sta->mesh->plid = plid; 1103 sta->mesh->plid = plid;
1072 sta->sta.aid = plid;
1073 } else if (!sta && event == OPN_RJCT) { 1104 } else if (!sta && event == OPN_RJCT) {
1074 mesh_plink_frame_tx(sdata, NULL, WLAN_SP_MESH_PEERING_CLOSE, 1105 mesh_plink_frame_tx(sdata, NULL, WLAN_SP_MESH_PEERING_CLOSE,
1075 mgmt->sa, 0, plid, 1106 mgmt->sa, 0, plid,
@@ -1082,10 +1113,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
1082 1113
1083 if (event == CNF_ACPT) { 1114 if (event == CNF_ACPT) {
1084 /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */ 1115 /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */
1085 if (!sta->mesh->plid) { 1116 if (!sta->mesh->plid)
1086 sta->mesh->plid = plid; 1117 sta->mesh->plid = plid;
1087 sta->sta.aid = sta->mesh->plid;
1088 }
1089 1118
1090 sta->mesh->aid = get_unaligned_le16(PLINK_CNF_AID(mgmt)); 1119 sta->mesh->aid = get_unaligned_le16(PLINK_CNF_AID(mgmt));
1091 } 1120 }