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
					
				| @ -844,6 +844,111 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, | ||||
| 	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 | ||||
| mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | ||||
| 			 struct ieee80211_mgmt *mgmt, | ||||
| @ -853,9 +958,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | ||||
| 	struct sta_info *sta; | ||||
| 	enum plink_event event; | ||||
| 	enum ieee80211_self_protected_actioncode ftype; | ||||
| 	bool matches_local; | ||||
| 	u32 changed = 0; | ||||
| 	u8 ie_len; | ||||
| 	u8 ie_len = elems->peering_len; | ||||
| 	__le16 plid, llid = 0; | ||||
| 
 | ||||
| 	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; | ||||
| 	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 | ||||
| @ -901,9 +1004,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | ||||
| 
 | ||||
| 	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 && | ||||
| 	    !rssi_threshold_check(sdata, sta)) { | ||||
| 		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; | ||||
| 	} | ||||
| 
 | ||||
| 	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... */ | ||||
| 	event = PLINK_UNDEFINED; | ||||
| 
 | ||||
| 	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; | ||||
| 		} | ||||
| 	} | ||||
| 	event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid); | ||||
| 
 | ||||
| 	if (event == OPN_ACPT) { | ||||
| 		rcu_read_unlock(); | ||||
| @ -996,6 +1023,14 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | ||||
| 			goto unlock_rcu; | ||||
| 		} | ||||
| 		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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user