aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-10-26 11:53:44 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-01-03 07:01:40 -0500
commitd582cffbcd04eae0bd8a83b05648bfd54bfd21c9 (patch)
treed6832e35977669df448c196db95ecf6b4e399c2b
parentdfa674da1807bc8fb782fc38a7d48c8ea3168eb7 (diff)
nl80211/mac80211: support full station state in AP mode
Today, stations are added already associated. That is inefficient if, for example, the driver has no room for stations any more because then the station will go through the entire auth/assoc handshake, only to be kicked out afterwards. To address this a bit better, at least with drivers using the new station state callback, allow hostapd to add stations in unauthenticated mode, just after receiving the AUTH frame, before even replying. Thus if there's no more space at that point, it can send a negative auth frame back. It still needs to handle later state transition errors though, of course. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/uapi/linux/nl80211.h16
-rw-r--r--net/mac80211/cfg.c115
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/wireless/nl80211.c24
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 */
3144enum nl80211_feature_flags { 3159enum 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
1083static 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
1080static int sta_apply_parameters(struct ieee80211_local *local, 1135static 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;