diff options
author | Thomas Pedersen <thomas@cozybit.com> | 2013-11-05 14:17:03 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-11-25 14:50:26 -0500 |
commit | c99a89edb1066e4c1f79b3ca4e91a676d1b25ce1 (patch) | |
tree | ea5c09ff2ad8095807a8deaeee2857b0d2fdfe55 /net/mac80211/mesh_plink.c | |
parent | c7e678115a2693782a9950d33b1a2e602e2c6b70 (diff) |
mac80211: factor out plink event gathering
Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 195 |
1 files changed, 115 insertions, 80 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 4311d4571ec8..ee2a97f31732 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -844,6 +844,111 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, | |||
844 | return changed; | 844 | return changed; |
845 | } | 845 | } |
846 | 846 | ||
847 | /* | ||
848 | * mesh_plink_get_event - get correct MPM event | ||
849 | * | ||
850 | * @sdata: interface | ||
851 | * @sta: peer, leave NULL if processing a frame from a new suitable peer | ||
852 | * @elems: peering management IEs | ||
853 | * @ftype: frame type | ||
854 | * @llid: peer's peer link ID | ||
855 | * @plid: peer's local link ID | ||
856 | * | ||
857 | * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as | ||
858 | * an error. | ||
859 | */ | ||
860 | static enum plink_event | ||
861 | mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, | ||
862 | struct sta_info *sta, | ||
863 | struct ieee802_11_elems *elems, | ||
864 | enum ieee80211_self_protected_actioncode ftype, | ||
865 | __le16 llid, __le16 plid) | ||
866 | { | ||
867 | enum plink_event event = PLINK_UNDEFINED; | ||
868 | u8 ie_len = elems->peering_len; | ||
869 | bool matches_local; | ||
870 | |||
871 | matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || | ||
872 | mesh_matches_local(sdata, elems)); | ||
873 | |||
874 | /* deny open request from non-matching peer */ | ||
875 | if (!matches_local && !sta) { | ||
876 | event = OPN_RJCT; | ||
877 | goto out; | ||
878 | } | ||
879 | |||
880 | if (!sta) { | ||
881 | if (ftype != WLAN_SP_MESH_PEERING_OPEN) { | ||
882 | mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); | ||
883 | goto out; | ||
884 | } | ||
885 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ | ||
886 | if (!mesh_plink_free_count(sdata)) { | ||
887 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); | ||
888 | goto out; | ||
889 | } | ||
890 | } else { | ||
891 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
892 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); | ||
893 | goto out; | ||
894 | } | ||
895 | if (sta->plink_state == NL80211_PLINK_BLOCKED) | ||
896 | goto out; | ||
897 | } | ||
898 | |||
899 | /* new matching peer */ | ||
900 | if (!sta) { | ||
901 | event = OPN_ACPT; | ||
902 | goto out; | ||
903 | } | ||
904 | |||
905 | switch (ftype) { | ||
906 | case WLAN_SP_MESH_PEERING_OPEN: | ||
907 | if (!matches_local) | ||
908 | event = OPN_RJCT; | ||
909 | if (!mesh_plink_free_count(sdata) || | ||
910 | (sta->plid && sta->plid != plid)) | ||
911 | event = OPN_IGNR; | ||
912 | else | ||
913 | event = OPN_ACPT; | ||
914 | break; | ||
915 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
916 | if (!matches_local) | ||
917 | event = CNF_RJCT; | ||
918 | if (!mesh_plink_free_count(sdata) || | ||
919 | (sta->llid != llid || sta->plid != plid)) | ||
920 | event = CNF_IGNR; | ||
921 | else | ||
922 | event = CNF_ACPT; | ||
923 | break; | ||
924 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
925 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
926 | /* Do not check for llid or plid. This does not | ||
927 | * follow the standard but since multiple plinks | ||
928 | * per sta are not supported, it is necessary in | ||
929 | * order to avoid a livelock when MP A sees an | ||
930 | * establish peer link to MP B but MP B does not | ||
931 | * see it. This can be caused by a timeout in | ||
932 | * B's peer link establishment or B beign | ||
933 | * restarted. | ||
934 | */ | ||
935 | event = CLS_ACPT; | ||
936 | else if (sta->plid != plid) | ||
937 | event = CLS_IGNR; | ||
938 | else if (ie_len == 8 && sta->llid != llid) | ||
939 | event = CLS_IGNR; | ||
940 | else | ||
941 | event = CLS_ACPT; | ||
942 | break; | ||
943 | default: | ||
944 | mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); | ||
945 | break; | ||
946 | } | ||
947 | |||
948 | out: | ||
949 | return event; | ||
950 | } | ||
951 | |||
847 | static void | 952 | static void |
848 | mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | 953 | mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, |
849 | struct ieee80211_mgmt *mgmt, | 954 | struct ieee80211_mgmt *mgmt, |
@@ -853,9 +958,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
853 | struct sta_info *sta; | 958 | struct sta_info *sta; |
854 | enum plink_event event; | 959 | enum plink_event event; |
855 | enum ieee80211_self_protected_actioncode ftype; | 960 | enum ieee80211_self_protected_actioncode ftype; |
856 | bool matches_local; | ||
857 | u32 changed = 0; | 961 | u32 changed = 0; |
858 | u8 ie_len; | 962 | u8 ie_len = elems->peering_len; |
859 | __le16 plid, llid = 0; | 963 | __le16 plid, llid = 0; |
860 | 964 | ||
861 | if (!elems->peering) { | 965 | if (!elems->peering) { |
@@ -872,7 +976,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
872 | } | 976 | } |
873 | 977 | ||
874 | ftype = mgmt->u.action.u.self_prot.action_code; | 978 | ftype = mgmt->u.action.u.self_prot.action_code; |
875 | ie_len = elems->peering_len; | ||
876 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || | 979 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || |
877 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || | 980 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || |
878 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 | 981 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 |
@@ -901,9 +1004,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
901 | 1004 | ||
902 | sta = sta_info_get(sdata, mgmt->sa); | 1005 | sta = sta_info_get(sdata, mgmt->sa); |
903 | 1006 | ||
904 | matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || | ||
905 | mesh_matches_local(sdata, elems)); | ||
906 | |||
907 | if (ftype == WLAN_SP_MESH_PEERING_OPEN && | 1007 | if (ftype == WLAN_SP_MESH_PEERING_OPEN && |
908 | !rssi_threshold_check(sdata, sta)) { | 1008 | !rssi_threshold_check(sdata, sta)) { |
909 | mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", | 1009 | 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, | |||
911 | goto unlock_rcu; | 1011 | goto unlock_rcu; |
912 | } | 1012 | } |
913 | 1013 | ||
914 | if (!sta) { | ||
915 | if (ftype != WLAN_SP_MESH_PEERING_OPEN) { | ||
916 | mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); | ||
917 | goto unlock_rcu; | ||
918 | } | ||
919 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ | ||
920 | if (!mesh_plink_free_count(sdata)) { | ||
921 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); | ||
922 | goto unlock_rcu; | ||
923 | } | ||
924 | /* deny open request from non-matching peer */ | ||
925 | if (!matches_local) { | ||
926 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
927 | mgmt->sa, 0, plid, | ||
928 | cpu_to_le16(WLAN_REASON_MESH_CONFIG)); | ||
929 | goto unlock_rcu; | ||
930 | } | ||
931 | } else { | ||
932 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
933 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); | ||
934 | goto unlock_rcu; | ||
935 | } | ||
936 | if (sta->plink_state == NL80211_PLINK_BLOCKED) | ||
937 | goto unlock_rcu; | ||
938 | } | ||
939 | |||
940 | /* Now we will figure out the appropriate event... */ | 1014 | /* Now we will figure out the appropriate event... */ |
941 | event = PLINK_UNDEFINED; | 1015 | event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid); |
942 | |||
943 | if (!sta) | ||
944 | event = OPN_ACPT; | ||
945 | else { | ||
946 | switch (ftype) { | ||
947 | case WLAN_SP_MESH_PEERING_OPEN: | ||
948 | if (!matches_local) | ||
949 | event = OPN_RJCT; | ||
950 | else if (!mesh_plink_free_count(sdata) || | ||
951 | (sta->plid && sta->plid != plid)) | ||
952 | event = OPN_IGNR; | ||
953 | else | ||
954 | event = OPN_ACPT; | ||
955 | break; | ||
956 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
957 | if (!matches_local) | ||
958 | event = CNF_RJCT; | ||
959 | else if (!mesh_plink_free_count(sdata) || | ||
960 | (sta->llid != llid || sta->plid != plid)) | ||
961 | event = CNF_IGNR; | ||
962 | else | ||
963 | event = CNF_ACPT; | ||
964 | break; | ||
965 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
966 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
967 | /* Do not check for llid or plid. This does not | ||
968 | * follow the standard but since multiple plinks | ||
969 | * per sta are not supported, it is necessary in | ||
970 | * order to avoid a livelock when MP A sees an | ||
971 | * establish peer link to MP B but MP B does not | ||
972 | * see it. This can be caused by a timeout in | ||
973 | * B's peer link establishment or B beign | ||
974 | * restarted. | ||
975 | */ | ||
976 | event = CLS_ACPT; | ||
977 | else if (sta->plid != plid) | ||
978 | event = CLS_IGNR; | ||
979 | else if (ie_len == 8 && sta->llid != llid) | ||
980 | event = CLS_IGNR; | ||
981 | else | ||
982 | event = CLS_ACPT; | ||
983 | break; | ||
984 | default: | ||
985 | mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); | ||
986 | goto unlock_rcu; | ||
987 | } | ||
988 | } | ||
989 | 1016 | ||
990 | if (event == OPN_ACPT) { | 1017 | if (event == OPN_ACPT) { |
991 | rcu_read_unlock(); | 1018 | rcu_read_unlock(); |
@@ -996,6 +1023,14 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
996 | goto unlock_rcu; | 1023 | goto unlock_rcu; |
997 | } | 1024 | } |
998 | sta->plid = plid; | 1025 | sta->plid = plid; |
1026 | } else if (!sta && event == OPN_RJCT) { | ||
1027 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
1028 | mgmt->sa, 0, plid, | ||
1029 | cpu_to_le16(WLAN_REASON_MESH_CONFIG)); | ||
1030 | goto unlock_rcu; | ||
1031 | } else if (!sta || event == PLINK_UNDEFINED) { | ||
1032 | /* something went wrong */ | ||
1033 | goto unlock_rcu; | ||
999 | } | 1034 | } |
1000 | 1035 | ||
1001 | changed |= mesh_plink_fsm(sdata, sta, event); | 1036 | changed |= mesh_plink_fsm(sdata, sta, event); |