Commit c99a89ed authored by Thomas Pedersen's avatar Thomas Pedersen Committed by Johannes Berg

mac80211: factor out plink event gathering

Signed-off-by: default avatarThomas Pedersen <thomas@cozybit.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent c7e67811
...@@ -844,110 +844,69 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, ...@@ -844,110 +844,69 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
return changed; return changed;
} }
static void /*
mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, * mesh_plink_get_event - get correct MPM event
struct ieee80211_mgmt *mgmt, *
struct ieee802_11_elems *elems) * @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;
struct sta_info *sta; u8 ie_len = elems->peering_len;
enum plink_event event;
enum ieee80211_self_protected_actioncode ftype;
bool matches_local; bool matches_local;
u32 changed = 0;
u8 ie_len;
__le16 plid, llid = 0;
if (!elems->peering) {
mpl_dbg(sdata,
"Mesh plink: missing necessary peer link ie\n");
return;
}
if (elems->rsn_len &&
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
mpl_dbg(sdata,
"Mesh plink: can't establish link with secure peer\n");
return;
}
ftype = mgmt->u.action.u.self_prot.action_code;
ie_len = elems->peering_len;
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
&& ie_len != 8)) {
mpl_dbg(sdata,
"Mesh plink: incorrect plink ie length %d %d\n",
ftype, ie_len);
return;
}
if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
(!elems->mesh_id || !elems->mesh_config)) {
mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
return;
}
/* Note the lines below are correct, the llid in the frame is the plid
* from the point of view of this host.
*/
memcpy(&plid, PLINK_GET_LLID(elems->peering), 2);
if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
memcpy(&llid, PLINK_GET_PLID(elems->peering), 2);
/* WARNING: Only for sta pointer, is dropped & re-acquired */
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->sa);
matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
mesh_matches_local(sdata, elems)); mesh_matches_local(sdata, elems));
if (ftype == WLAN_SP_MESH_PEERING_OPEN && /* deny open request from non-matching peer */
!rssi_threshold_check(sdata, sta)) { if (!matches_local && !sta) {
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", event = OPN_RJCT;
mgmt->sa); goto out;
goto unlock_rcu;
} }
if (!sta) { if (!sta) {
if (ftype != WLAN_SP_MESH_PEERING_OPEN) { if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
goto unlock_rcu; goto out;
} }
/* ftype == WLAN_SP_MESH_PEERING_OPEN */ /* ftype == WLAN_SP_MESH_PEERING_OPEN */
if (!mesh_plink_free_count(sdata)) { if (!mesh_plink_free_count(sdata)) {
mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
goto unlock_rcu; goto out;
}
/* 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 { } else {
if (!test_sta_flag(sta, WLAN_STA_AUTH)) { if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
goto unlock_rcu; goto out;
} }
if (sta->plink_state == NL80211_PLINK_BLOCKED) if (sta->plink_state == NL80211_PLINK_BLOCKED)
goto unlock_rcu; goto out;
} }
/* Now we will figure out the appropriate event... */ /* new matching peer */
event = PLINK_UNDEFINED; if (!sta) {
if (!sta)
event = OPN_ACPT; event = OPN_ACPT;
else { goto out;
}
switch (ftype) { switch (ftype) {
case WLAN_SP_MESH_PEERING_OPEN: case WLAN_SP_MESH_PEERING_OPEN:
if (!matches_local) if (!matches_local)
event = OPN_RJCT; event = OPN_RJCT;
else if (!mesh_plink_free_count(sdata) || if (!mesh_plink_free_count(sdata) ||
(sta->plid && sta->plid != plid)) (sta->plid && sta->plid != plid))
event = OPN_IGNR; event = OPN_IGNR;
else else
...@@ -956,7 +915,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, ...@@ -956,7 +915,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
case WLAN_SP_MESH_PEERING_CONFIRM: case WLAN_SP_MESH_PEERING_CONFIRM:
if (!matches_local) if (!matches_local)
event = CNF_RJCT; event = CNF_RJCT;
else if (!mesh_plink_free_count(sdata) || if (!mesh_plink_free_count(sdata) ||
(sta->llid != llid || sta->plid != plid)) (sta->llid != llid || sta->plid != plid))
event = CNF_IGNR; event = CNF_IGNR;
else else
...@@ -983,10 +942,78 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, ...@@ -983,10 +942,78 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
break; break;
default: default:
mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
goto unlock_rcu; break;
}
out:
return event;
}
static void
mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems)
{
struct sta_info *sta;
enum plink_event event;
enum ieee80211_self_protected_actioncode ftype;
u32 changed = 0;
u8 ie_len = elems->peering_len;
__le16 plid, llid = 0;
if (!elems->peering) {
mpl_dbg(sdata,
"Mesh plink: missing necessary peer link ie\n");
return;
} }
if (elems->rsn_len &&
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
mpl_dbg(sdata,
"Mesh plink: can't establish link with secure peer\n");
return;
} }
ftype = mgmt->u.action.u.self_prot.action_code;
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
&& ie_len != 8)) {
mpl_dbg(sdata,
"Mesh plink: incorrect plink ie length %d %d\n",
ftype, ie_len);
return;
}
if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
(!elems->mesh_id || !elems->mesh_config)) {
mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
return;
}
/* Note the lines below are correct, the llid in the frame is the plid
* from the point of view of this host.
*/
memcpy(&plid, PLINK_GET_LLID(elems->peering), 2);
if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
memcpy(&llid, PLINK_GET_PLID(elems->peering), 2);
/* WARNING: Only for sta pointer, is dropped & re-acquired */
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->sa);
if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
!rssi_threshold_check(sdata, sta)) {
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
mgmt->sa);
goto unlock_rcu;
}
/* Now we will figure out the appropriate event... */
event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid);
if (event == OPN_ACPT) { if (event == OPN_ACPT) {
rcu_read_unlock(); rcu_read_unlock();
/* allocate sta entry if necessary and update info */ /* allocate sta entry if necessary and update info */
...@@ -996,6 +1023,14 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment