mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
mac80211: factor out plink event gathering
Signed-off-by: Thomas Pedersen <thomas@cozybit.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
c7e678115a
commit
c99a89edb1
1 changed files with 115 additions and 80 deletions
|
@ -844,6 +844,111 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mesh_plink_get_event - get correct MPM event
|
||||||
|
*
|
||||||
|
* @sdata: interface
|
||||||
|
* @sta: peer, leave NULL if processing a frame from a new suitable peer
|
||||||
|
* @elems: peering management IEs
|
||||||
|
* @ftype: frame type
|
||||||
|
* @llid: peer's peer link ID
|
||||||
|
* @plid: peer's local link ID
|
||||||
|
*
|
||||||
|
* Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as
|
||||||
|
* an error.
|
||||||
|
*/
|
||||||
|
static enum plink_event
|
||||||
|
mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct sta_info *sta,
|
||||||
|
struct ieee802_11_elems *elems,
|
||||||
|
enum ieee80211_self_protected_actioncode ftype,
|
||||||
|
__le16 llid, __le16 plid)
|
||||||
|
{
|
||||||
|
enum plink_event event = PLINK_UNDEFINED;
|
||||||
|
u8 ie_len = elems->peering_len;
|
||||||
|
bool matches_local;
|
||||||
|
|
||||||
|
matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
|
||||||
|
mesh_matches_local(sdata, elems));
|
||||||
|
|
||||||
|
/* deny open request from non-matching peer */
|
||||||
|
if (!matches_local && !sta) {
|
||||||
|
event = OPN_RJCT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sta) {
|
||||||
|
if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
|
||||||
|
mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* ftype == WLAN_SP_MESH_PEERING_OPEN */
|
||||||
|
if (!mesh_plink_free_count(sdata)) {
|
||||||
|
mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
|
||||||
|
mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (sta->plink_state == NL80211_PLINK_BLOCKED)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* new matching peer */
|
||||||
|
if (!sta) {
|
||||||
|
event = OPN_ACPT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ftype) {
|
||||||
|
case WLAN_SP_MESH_PEERING_OPEN:
|
||||||
|
if (!matches_local)
|
||||||
|
event = OPN_RJCT;
|
||||||
|
if (!mesh_plink_free_count(sdata) ||
|
||||||
|
(sta->plid && sta->plid != plid))
|
||||||
|
event = OPN_IGNR;
|
||||||
|
else
|
||||||
|
event = OPN_ACPT;
|
||||||
|
break;
|
||||||
|
case WLAN_SP_MESH_PEERING_CONFIRM:
|
||||||
|
if (!matches_local)
|
||||||
|
event = CNF_RJCT;
|
||||||
|
if (!mesh_plink_free_count(sdata) ||
|
||||||
|
(sta->llid != llid || sta->plid != plid))
|
||||||
|
event = CNF_IGNR;
|
||||||
|
else
|
||||||
|
event = CNF_ACPT;
|
||||||
|
break;
|
||||||
|
case WLAN_SP_MESH_PEERING_CLOSE:
|
||||||
|
if (sta->plink_state == NL80211_PLINK_ESTAB)
|
||||||
|
/* Do not check for llid or plid. This does not
|
||||||
|
* follow the standard but since multiple plinks
|
||||||
|
* per sta are not supported, it is necessary in
|
||||||
|
* order to avoid a livelock when MP A sees an
|
||||||
|
* establish peer link to MP B but MP B does not
|
||||||
|
* see it. This can be caused by a timeout in
|
||||||
|
* B's peer link establishment or B beign
|
||||||
|
* restarted.
|
||||||
|
*/
|
||||||
|
event = CLS_ACPT;
|
||||||
|
else if (sta->plid != plid)
|
||||||
|
event = CLS_IGNR;
|
||||||
|
else if (ie_len == 8 && sta->llid != llid)
|
||||||
|
event = CLS_IGNR;
|
||||||
|
else
|
||||||
|
event = CLS_ACPT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
|
mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
struct ieee80211_mgmt *mgmt,
|
struct ieee80211_mgmt *mgmt,
|
||||||
|
@ -853,9 +958,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
enum plink_event event;
|
enum plink_event event;
|
||||||
enum ieee80211_self_protected_actioncode ftype;
|
enum ieee80211_self_protected_actioncode ftype;
|
||||||
bool matches_local;
|
|
||||||
u32 changed = 0;
|
u32 changed = 0;
|
||||||
u8 ie_len;
|
u8 ie_len = elems->peering_len;
|
||||||
__le16 plid, llid = 0;
|
__le16 plid, llid = 0;
|
||||||
|
|
||||||
if (!elems->peering) {
|
if (!elems->peering) {
|
||||||
|
@ -872,7 +976,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
ftype = mgmt->u.action.u.self_prot.action_code;
|
ftype = mgmt->u.action.u.self_prot.action_code;
|
||||||
ie_len = elems->peering_len;
|
|
||||||
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
|
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
|
||||||
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
|
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
|
||||||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
|
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
|
||||||
|
@ -901,9 +1004,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
sta = sta_info_get(sdata, mgmt->sa);
|
sta = sta_info_get(sdata, mgmt->sa);
|
||||||
|
|
||||||
matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
|
|
||||||
mesh_matches_local(sdata, elems));
|
|
||||||
|
|
||||||
if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
|
if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
|
||||||
!rssi_threshold_check(sdata, sta)) {
|
!rssi_threshold_check(sdata, sta)) {
|
||||||
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
|
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
|
||||||
|
@ -911,81 +1011,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
goto unlock_rcu;
|
goto unlock_rcu;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sta) {
|
|
||||||
if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
|
|
||||||
mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
|
|
||||||
goto unlock_rcu;
|
|
||||||
}
|
|
||||||
/* ftype == WLAN_SP_MESH_PEERING_OPEN */
|
|
||||||
if (!mesh_plink_free_count(sdata)) {
|
|
||||||
mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
|
|
||||||
goto unlock_rcu;
|
|
||||||
}
|
|
||||||
/* deny open request from non-matching peer */
|
|
||||||
if (!matches_local) {
|
|
||||||
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
|
|
||||||
mgmt->sa, 0, plid,
|
|
||||||
cpu_to_le16(WLAN_REASON_MESH_CONFIG));
|
|
||||||
goto unlock_rcu;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
|
|
||||||
mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
|
|
||||||
goto unlock_rcu;
|
|
||||||
}
|
|
||||||
if (sta->plink_state == NL80211_PLINK_BLOCKED)
|
|
||||||
goto unlock_rcu;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we will figure out the appropriate event... */
|
/* Now we will figure out the appropriate event... */
|
||||||
event = PLINK_UNDEFINED;
|
event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid);
|
||||||
|
|
||||||
if (!sta)
|
|
||||||
event = OPN_ACPT;
|
|
||||||
else {
|
|
||||||
switch (ftype) {
|
|
||||||
case WLAN_SP_MESH_PEERING_OPEN:
|
|
||||||
if (!matches_local)
|
|
||||||
event = OPN_RJCT;
|
|
||||||
else if (!mesh_plink_free_count(sdata) ||
|
|
||||||
(sta->plid && sta->plid != plid))
|
|
||||||
event = OPN_IGNR;
|
|
||||||
else
|
|
||||||
event = OPN_ACPT;
|
|
||||||
break;
|
|
||||||
case WLAN_SP_MESH_PEERING_CONFIRM:
|
|
||||||
if (!matches_local)
|
|
||||||
event = CNF_RJCT;
|
|
||||||
else if (!mesh_plink_free_count(sdata) ||
|
|
||||||
(sta->llid != llid || sta->plid != plid))
|
|
||||||
event = CNF_IGNR;
|
|
||||||
else
|
|
||||||
event = CNF_ACPT;
|
|
||||||
break;
|
|
||||||
case WLAN_SP_MESH_PEERING_CLOSE:
|
|
||||||
if (sta->plink_state == NL80211_PLINK_ESTAB)
|
|
||||||
/* Do not check for llid or plid. This does not
|
|
||||||
* follow the standard but since multiple plinks
|
|
||||||
* per sta are not supported, it is necessary in
|
|
||||||
* order to avoid a livelock when MP A sees an
|
|
||||||
* establish peer link to MP B but MP B does not
|
|
||||||
* see it. This can be caused by a timeout in
|
|
||||||
* B's peer link establishment or B beign
|
|
||||||
* restarted.
|
|
||||||
*/
|
|
||||||
event = CLS_ACPT;
|
|
||||||
else if (sta->plid != plid)
|
|
||||||
event = CLS_IGNR;
|
|
||||||
else if (ie_len == 8 && sta->llid != llid)
|
|
||||||
event = CLS_IGNR;
|
|
||||||
else
|
|
||||||
event = CLS_ACPT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
|
|
||||||
goto unlock_rcu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event == OPN_ACPT) {
|
if (event == OPN_ACPT) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
@ -996,6 +1023,14 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
goto unlock_rcu;
|
goto unlock_rcu;
|
||||||
}
|
}
|
||||||
sta->plid = plid;
|
sta->plid = plid;
|
||||||
|
} else if (!sta && event == OPN_RJCT) {
|
||||||
|
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
|
||||||
|
mgmt->sa, 0, plid,
|
||||||
|
cpu_to_le16(WLAN_REASON_MESH_CONFIG));
|
||||||
|
goto unlock_rcu;
|
||||||
|
} else if (!sta || event == PLINK_UNDEFINED) {
|
||||||
|
/* something went wrong */
|
||||||
|
goto unlock_rcu;
|
||||||
}
|
}
|
||||||
|
|
||||||
changed |= mesh_plink_fsm(sdata, sta, event);
|
changed |= mesh_plink_fsm(sdata, sta, event);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue