|
@@ -82,20 +82,14 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * NOTE: This is just an alias for sta_info_alloc(), see notes
|
|
|
- * on it in the lifecycle management section!
|
|
|
+ * Allocate mesh sta entry and insert into station table
|
|
|
*/
|
|
|
static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
|
|
|
- u8 *hw_addr, u32 rates,
|
|
|
- struct ieee802_11_elems *elems)
|
|
|
+ u8 *hw_addr)
|
|
|
{
|
|
|
- struct ieee80211_local *local = sdata->local;
|
|
|
- struct ieee80211_supported_band *sband;
|
|
|
struct sta_info *sta;
|
|
|
|
|
|
- sband = local->hw.wiphy->bands[local->oper_channel->band];
|
|
|
-
|
|
|
- if (local->num_sta >= MESH_MAX_PLINKS)
|
|
|
+ if (sdata->local->num_sta >= MESH_MAX_PLINKS)
|
|
|
return NULL;
|
|
|
|
|
|
sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
|
|
@@ -108,12 +102,8 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
|
set_sta_flag(sta, WLAN_STA_WME);
|
|
|
|
|
|
- sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
|
|
|
- if (elems->ht_cap_elem)
|
|
|
- ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
|
|
- elems->ht_cap_elem,
|
|
|
- &sta->sta.ht_cap);
|
|
|
- rate_control_rate_init(sta);
|
|
|
+ if (sta_info_insert(sta))
|
|
|
+ return NULL;
|
|
|
|
|
|
return sta;
|
|
|
}
|
|
@@ -274,43 +264,76 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-void mesh_neighbour_update(u8 *hw_addr, u32 rates,
|
|
|
- struct ieee80211_sub_if_data *sdata,
|
|
|
- struct ieee802_11_elems *elems)
|
|
|
+/* mesh_peer_init - initialize new mesh peer and return resulting sta_info
|
|
|
+ *
|
|
|
+ * @sdata: local meshif
|
|
|
+ * @addr: peer's address
|
|
|
+ * @rates: station's supported rates
|
|
|
+ * @elems: IEs from beacon or mesh peering frame
|
|
|
+ *
|
|
|
+ * call under RCU
|
|
|
+ */
|
|
|
+static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
|
|
|
+ u8 *addr, u32 rates,
|
|
|
+ struct ieee802_11_elems *elems)
|
|
|
{
|
|
|
struct ieee80211_local *local = sdata->local;
|
|
|
+ struct ieee80211_supported_band *sband;
|
|
|
struct sta_info *sta;
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
+ sband = local->hw.wiphy->bands[local->oper_channel->band];
|
|
|
|
|
|
- sta = sta_info_get(sdata, hw_addr);
|
|
|
+ sta = sta_info_get(sdata, addr);
|
|
|
if (!sta) {
|
|
|
- rcu_read_unlock();
|
|
|
- /* Userspace handles peer allocation when security is enabled
|
|
|
- * */
|
|
|
- if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
|
|
|
- cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
|
|
|
- elems->ie_start, elems->total_len,
|
|
|
- GFP_KERNEL);
|
|
|
- else
|
|
|
- sta = mesh_plink_alloc(sdata, hw_addr, rates, elems);
|
|
|
+ sta = mesh_plink_alloc(sdata, addr);
|
|
|
if (!sta)
|
|
|
- return;
|
|
|
- if (sta_info_insert_rcu(sta)) {
|
|
|
- rcu_read_unlock();
|
|
|
- return;
|
|
|
- }
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
+ spin_lock_bh(&sta->lock);
|
|
|
sta->last_rx = jiffies;
|
|
|
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
|
|
|
+ if (elems->ht_cap_elem)
|
|
|
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
|
|
+ elems->ht_cap_elem,
|
|
|
+ &sta->sta.ht_cap);
|
|
|
+ else
|
|
|
+ memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
|
|
|
+
|
|
|
+ rate_control_rate_init(sta);
|
|
|
+ spin_unlock_bh(&sta->lock);
|
|
|
+
|
|
|
+ return sta;
|
|
|
+}
|
|
|
+
|
|
|
+void mesh_neighbour_update(u8 *hw_addr, u32 rates,
|
|
|
+ struct ieee80211_sub_if_data *sdata,
|
|
|
+ struct ieee802_11_elems *elems)
|
|
|
+{
|
|
|
+ struct sta_info *sta;
|
|
|
+
|
|
|
+ /* Userspace handles peer allocation when security is enabled */
|
|
|
+ if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
|
|
|
+ cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
|
|
|
+ elems->ie_start,
|
|
|
+ elems->total_len,
|
|
|
+ GFP_KERNEL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+ sta = mesh_peer_init(sdata, hw_addr, rates, elems);
|
|
|
+ if (!sta)
|
|
|
+ goto out;
|
|
|
+
|
|
|
if (mesh_peer_accepts_plinks(elems) &&
|
|
|
- sta->plink_state == NL80211_PLINK_LISTEN &&
|
|
|
- sdata->u.mesh.accepting_plinks &&
|
|
|
- sdata->u.mesh.mshcfg.auto_open_plinks &&
|
|
|
- rssi_threshold_check(sta, sdata))
|
|
|
+ sta->plink_state == NL80211_PLINK_LISTEN &&
|
|
|
+ sdata->u.mesh.accepting_plinks &&
|
|
|
+ sdata->u.mesh.mshcfg.auto_open_plinks &&
|
|
|
+ rssi_threshold_check(sta, sdata))
|
|
|
mesh_plink_open(sta);
|
|
|
|
|
|
+out:
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|
|
@@ -587,26 +610,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|
|
return;
|
|
|
} else if (!sta) {
|
|
|
/* ftype == WLAN_SP_MESH_PEERING_OPEN */
|
|
|
-
|
|
|
- rcu_read_unlock();
|
|
|
-
|
|
|
if (!mesh_plink_free_count(sdata)) {
|
|
|
mpl_dbg("Mesh plink error: no more free plinks\n");
|
|
|
- return;
|
|
|
- }
|
|
|
- sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems);
|
|
|
- if (!sta) {
|
|
|
- mpl_dbg("Mesh plink error: plink table full\n");
|
|
|
- return;
|
|
|
- }
|
|
|
- if (sta_info_insert_rcu(sta)) {
|
|
|
rcu_read_unlock();
|
|
|
return;
|
|
|
}
|
|
|
event = OPN_ACPT;
|
|
|
- spin_lock_bh(&sta->lock);
|
|
|
} else if (matches_local) {
|
|
|
- spin_lock_bh(&sta->lock);
|
|
|
switch (ftype) {
|
|
|
case WLAN_SP_MESH_PEERING_OPEN:
|
|
|
if (!mesh_plink_free_count(sdata) ||
|
|
@@ -643,12 +653,19 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|
|
break;
|
|
|
default:
|
|
|
mpl_dbg("Mesh plink: unknown frame subtype\n");
|
|
|
- spin_unlock_bh(&sta->lock);
|
|
|
rcu_read_unlock();
|
|
|
return;
|
|
|
}
|
|
|
- } else {
|
|
|
- spin_lock_bh(&sta->lock);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (event == OPN_ACPT) {
|
|
|
+ /* allocate sta entry if necessary and update info */
|
|
|
+ sta = mesh_peer_init(sdata, mgmt->sa, rates, &elems);
|
|
|
+ if (!sta) {
|
|
|
+ mpl_dbg("Mesh plink: failed to init peer!\n");
|
|
|
+ rcu_read_unlock();
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
|
|
@@ -656,6 +673,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
|
|
le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
|
|
|
event);
|
|
|
reason = 0;
|
|
|
+ spin_lock_bh(&sta->lock);
|
|
|
switch (sta->plink_state) {
|
|
|
/* spin_unlock as soon as state is updated at each case */
|
|
|
case NL80211_PLINK_LISTEN:
|