diff options
-rw-r--r-- | include/uapi/linux/nl80211.h | 16 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 115 | ||||
-rw-r--r-- | net/mac80211/main.c | 3 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 24 |
4 files changed, 113 insertions, 45 deletions
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index e3e19f8b16f2..547017100a30 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -1697,6 +1697,9 @@ enum nl80211_iftype { | |||
1697 | * flag can't be changed, it is only valid while adding a station, and | 1697 | * flag can't be changed, it is only valid while adding a station, and |
1698 | * attempts to change it will silently be ignored (rather than rejected | 1698 | * attempts to change it will silently be ignored (rather than rejected |
1699 | * as errors.) | 1699 | * as errors.) |
1700 | * @NL80211_STA_FLAG_ASSOCIATED: station is associated; used with drivers | ||
1701 | * that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a | ||
1702 | * previously added station into associated state | ||
1700 | * @NL80211_STA_FLAG_MAX: highest station flag number currently defined | 1703 | * @NL80211_STA_FLAG_MAX: highest station flag number currently defined |
1701 | * @__NL80211_STA_FLAG_AFTER_LAST: internal use | 1704 | * @__NL80211_STA_FLAG_AFTER_LAST: internal use |
1702 | */ | 1705 | */ |
@@ -1708,6 +1711,7 @@ enum nl80211_sta_flags { | |||
1708 | NL80211_STA_FLAG_MFP, | 1711 | NL80211_STA_FLAG_MFP, |
1709 | NL80211_STA_FLAG_AUTHENTICATED, | 1712 | NL80211_STA_FLAG_AUTHENTICATED, |
1710 | NL80211_STA_FLAG_TDLS_PEER, | 1713 | NL80211_STA_FLAG_TDLS_PEER, |
1714 | NL80211_STA_FLAG_ASSOCIATED, | ||
1711 | 1715 | ||
1712 | /* keep last */ | 1716 | /* keep last */ |
1713 | __NL80211_STA_FLAG_AFTER_LAST, | 1717 | __NL80211_STA_FLAG_AFTER_LAST, |
@@ -3140,6 +3144,17 @@ enum nl80211_ap_sme_features { | |||
3140 | * setting | 3144 | * setting |
3141 | * @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic | 3145 | * @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic |
3142 | * powersave | 3146 | * powersave |
3147 | * @NL80211_FEATURE_FULL_AP_CLIENT_STATE: The driver supports full state | ||
3148 | * transitions for AP clients. Without this flag (and if the driver | ||
3149 | * doesn't have the AP SME in the device) the driver supports adding | ||
3150 | * stations only when they're associated and adds them in associated | ||
3151 | * state (to later be transitioned into authorized), with this flag | ||
3152 | * they should be added before even sending the authentication reply | ||
3153 | * and then transitioned into authenticated, associated and authorized | ||
3154 | * states using station flags. | ||
3155 | * Note that even for drivers that support this, the default is to add | ||
3156 | * stations in authenticated/associated state, so to add unauthenticated | ||
3157 | * stations the authenticated/associated bits have to be set in the mask. | ||
3143 | */ | 3158 | */ |
3144 | enum nl80211_feature_flags { | 3159 | enum nl80211_feature_flags { |
3145 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 3160 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
@@ -3155,6 +3170,7 @@ enum nl80211_feature_flags { | |||
3155 | NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, | 3170 | NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10, |
3156 | NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, | 3171 | NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11, |
3157 | NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, | 3172 | NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12, |
3173 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 13, | ||
3158 | }; | 3174 | }; |
3159 | 3175 | ||
3160 | /** | 3176 | /** |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3e7d557fd481..f4d12c71928d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -510,6 +510,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
510 | BIT(NL80211_STA_FLAG_WME) | | 510 | BIT(NL80211_STA_FLAG_WME) | |
511 | BIT(NL80211_STA_FLAG_MFP) | | 511 | BIT(NL80211_STA_FLAG_MFP) | |
512 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | 512 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | |
513 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
513 | BIT(NL80211_STA_FLAG_TDLS_PEER); | 514 | BIT(NL80211_STA_FLAG_TDLS_PEER); |
514 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | 515 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) |
515 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | 516 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); |
@@ -521,6 +522,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
521 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | 522 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); |
522 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | 523 | if (test_sta_flag(sta, WLAN_STA_AUTH)) |
523 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | 524 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); |
525 | if (test_sta_flag(sta, WLAN_STA_ASSOC)) | ||
526 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
524 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | 527 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) |
525 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | 528 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); |
526 | } | 529 | } |
@@ -1077,6 +1080,58 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) | |||
1077 | netif_rx_ni(skb); | 1080 | netif_rx_ni(skb); |
1078 | } | 1081 | } |
1079 | 1082 | ||
1083 | static int sta_apply_auth_flags(struct ieee80211_local *local, | ||
1084 | struct sta_info *sta, | ||
1085 | u32 mask, u32 set) | ||
1086 | { | ||
1087 | int ret; | ||
1088 | |||
1089 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) && | ||
1090 | set & BIT(NL80211_STA_FLAG_AUTHENTICATED) && | ||
1091 | !test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
1092 | ret = sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
1093 | if (ret) | ||
1094 | return ret; | ||
1095 | } | ||
1096 | |||
1097 | if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) && | ||
1098 | set & BIT(NL80211_STA_FLAG_ASSOCIATED) && | ||
1099 | !test_sta_flag(sta, WLAN_STA_ASSOC)) { | ||
1100 | ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
1101 | if (ret) | ||
1102 | return ret; | ||
1103 | } | ||
1104 | |||
1105 | if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | ||
1106 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
1107 | ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
1108 | else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1109 | ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
1110 | else | ||
1111 | ret = 0; | ||
1112 | if (ret) | ||
1113 | return ret; | ||
1114 | } | ||
1115 | |||
1116 | if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) && | ||
1117 | !(set & BIT(NL80211_STA_FLAG_ASSOCIATED)) && | ||
1118 | test_sta_flag(sta, WLAN_STA_ASSOC)) { | ||
1119 | ret = sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
1120 | if (ret) | ||
1121 | return ret; | ||
1122 | } | ||
1123 | |||
1124 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) && | ||
1125 | !(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) && | ||
1126 | test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
1127 | ret = sta_info_move_state(sta, IEEE80211_STA_NONE); | ||
1128 | if (ret) | ||
1129 | return ret; | ||
1130 | } | ||
1131 | |||
1132 | return 0; | ||
1133 | } | ||
1134 | |||
1080 | static int sta_apply_parameters(struct ieee80211_local *local, | 1135 | static int sta_apply_parameters(struct ieee80211_local *local, |
1081 | struct sta_info *sta, | 1136 | struct sta_info *sta, |
1082 | struct station_parameters *params) | 1137 | struct station_parameters *params) |
@@ -1094,52 +1149,20 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1094 | mask = params->sta_flags_mask; | 1149 | mask = params->sta_flags_mask; |
1095 | set = params->sta_flags_set; | 1150 | set = params->sta_flags_set; |
1096 | 1151 | ||
1097 | /* | 1152 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
1098 | * In mesh mode, we can clear AUTHENTICATED flag but must | 1153 | /* |
1099 | * also make ASSOCIATED follow appropriately for the driver | 1154 | * In mesh mode, ASSOCIATED isn't part of the nl80211 |
1100 | * API. See also below, after AUTHORIZED changes. | 1155 | * API but must follow AUTHENTICATED for driver state. |
1101 | */ | 1156 | */ |
1102 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { | 1157 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) |
1103 | /* cfg80211 should not allow this in non-mesh modes */ | 1158 | mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); |
1104 | if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif))) | 1159 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) |
1105 | return -EINVAL; | 1160 | set |= BIT(NL80211_STA_FLAG_ASSOCIATED); |
1106 | |||
1107 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) && | ||
1108 | !test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
1109 | ret = sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
1110 | if (ret) | ||
1111 | return ret; | ||
1112 | ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
1113 | if (ret) | ||
1114 | return ret; | ||
1115 | } | ||
1116 | } | ||
1117 | |||
1118 | if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | ||
1119 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
1120 | ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
1121 | else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1122 | ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
1123 | if (ret) | ||
1124 | return ret; | ||
1125 | } | ||
1126 | |||
1127 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { | ||
1128 | /* cfg80211 should not allow this in non-mesh modes */ | ||
1129 | if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif))) | ||
1130 | return -EINVAL; | ||
1131 | |||
1132 | if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) && | ||
1133 | test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
1134 | ret = sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
1135 | if (ret) | ||
1136 | return ret; | ||
1137 | ret = sta_info_move_state(sta, IEEE80211_STA_NONE); | ||
1138 | if (ret) | ||
1139 | return ret; | ||
1140 | } | ||
1141 | } | 1161 | } |
1142 | 1162 | ||
1163 | ret = sta_apply_auth_flags(local, sta, mask, set); | ||
1164 | if (ret) | ||
1165 | return ret; | ||
1143 | 1166 | ||
1144 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { | 1167 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { |
1145 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) | 1168 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) |
@@ -1273,6 +1296,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1273 | if (!sta) | 1296 | if (!sta) |
1274 | return -ENOMEM; | 1297 | return -ENOMEM; |
1275 | 1298 | ||
1299 | /* | ||
1300 | * defaults -- if userspace wants something else we'll | ||
1301 | * change it accordingly in sta_apply_parameters() | ||
1302 | */ | ||
1276 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 1303 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); |
1277 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | 1304 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); |
1278 | 1305 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e6514f240fce..39cfe8f10ad2 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -541,7 +541,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
541 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | | 541 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
542 | NL80211_FEATURE_SAE | | 542 | NL80211_FEATURE_SAE | |
543 | NL80211_FEATURE_HT_IBSS | | 543 | NL80211_FEATURE_HT_IBSS | |
544 | NL80211_FEATURE_VIF_TXPOWER; | 544 | NL80211_FEATURE_VIF_TXPOWER | |
545 | NL80211_FEATURE_FULL_AP_CLIENT_STATE; | ||
545 | 546 | ||
546 | if (!ops->hw_scan) | 547 | if (!ops->hw_scan) |
547 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | 548 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b3cf7cc0d4a1..087f68ba6d7a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3231,11 +3231,21 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3231 | /* accept only the listed bits */ | 3231 | /* accept only the listed bits */ |
3232 | if (params.sta_flags_mask & | 3232 | if (params.sta_flags_mask & |
3233 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | 3233 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | |
3234 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3235 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
3234 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | 3236 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | |
3235 | BIT(NL80211_STA_FLAG_WME) | | 3237 | BIT(NL80211_STA_FLAG_WME) | |
3236 | BIT(NL80211_STA_FLAG_MFP))) | 3238 | BIT(NL80211_STA_FLAG_MFP))) |
3237 | return -EINVAL; | 3239 | return -EINVAL; |
3238 | 3240 | ||
3241 | /* but authenticated/associated only if driver handles it */ | ||
3242 | if (!(rdev->wiphy.features & | ||
3243 | NL80211_FEATURE_FULL_AP_CLIENT_STATE) && | ||
3244 | params.sta_flags_mask & | ||
3245 | (BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3246 | BIT(NL80211_STA_FLAG_ASSOCIATED))) | ||
3247 | return -EINVAL; | ||
3248 | |||
3239 | /* must be last in here for error handling */ | 3249 | /* must be last in here for error handling */ |
3240 | params.vlan = get_vlan(info, rdev); | 3250 | params.vlan = get_vlan(info, rdev); |
3241 | if (IS_ERR(params.vlan)) | 3251 | if (IS_ERR(params.vlan)) |
@@ -3393,17 +3403,31 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3393 | /* but don't bother the driver with it */ | 3403 | /* but don't bother the driver with it */ |
3394 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | 3404 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); |
3395 | 3405 | ||
3406 | /* allow authenticated/associated only if driver handles it */ | ||
3407 | if (!(rdev->wiphy.features & | ||
3408 | NL80211_FEATURE_FULL_AP_CLIENT_STATE) && | ||
3409 | params.sta_flags_mask & | ||
3410 | (BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3411 | BIT(NL80211_STA_FLAG_ASSOCIATED))) | ||
3412 | return -EINVAL; | ||
3413 | |||
3396 | /* must be last in here for error handling */ | 3414 | /* must be last in here for error handling */ |
3397 | params.vlan = get_vlan(info, rdev); | 3415 | params.vlan = get_vlan(info, rdev); |
3398 | if (IS_ERR(params.vlan)) | 3416 | if (IS_ERR(params.vlan)) |
3399 | return PTR_ERR(params.vlan); | 3417 | return PTR_ERR(params.vlan); |
3400 | break; | 3418 | break; |
3401 | case NL80211_IFTYPE_MESH_POINT: | 3419 | case NL80211_IFTYPE_MESH_POINT: |
3420 | /* associated is disallowed */ | ||
3421 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | ||
3422 | return -EINVAL; | ||
3402 | /* TDLS peers cannot be added */ | 3423 | /* TDLS peers cannot be added */ |
3403 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | 3424 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) |
3404 | return -EINVAL; | 3425 | return -EINVAL; |
3405 | break; | 3426 | break; |
3406 | case NL80211_IFTYPE_STATION: | 3427 | case NL80211_IFTYPE_STATION: |
3428 | /* associated is disallowed */ | ||
3429 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | ||
3430 | return -EINVAL; | ||
3407 | /* Only TDLS peers can be added */ | 3431 | /* Only TDLS peers can be added */ |
3408 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | 3432 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) |
3409 | return -EINVAL; | 3433 | return -EINVAL; |