cfg80211: handle add_station auth/assoc flag quirks
[cascardo/linux.git] / net / wireless / nl80211.c
index f4afa99..72de698 100644 (file)
@@ -4359,6 +4359,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        struct net_device *dev = info->user_ptr[1];
        struct station_parameters params;
        u8 *mac_addr = NULL;
+       u32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                        BIT(NL80211_STA_FLAG_ASSOCIATED);
 
        memset(&params, 0, sizeof(params));
 
@@ -4470,10 +4472,23 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                /* allow authenticated/associated only if driver handles it */
                if (!(rdev->wiphy.features &
                                NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
-                   params.sta_flags_mask &
-                               (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
-                                BIT(NL80211_STA_FLAG_ASSOCIATED)))
-                       return -EINVAL;
+                   params.sta_flags_mask & auth_assoc)
+                       return -EINVAL;
+
+               /* Older userspace, or userspace wanting to be compatible with
+                * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
+                * and assoc flags in the mask, but assumes the station will be
+                * added as associated anyway since this was the required driver
+                * behaviour before NL80211_FEATURE_FULL_AP_CLIENT_STATE was
+                * introduced.
+                * In order to not bother drivers with this quirk in the API
+                * set the flags in both the mask and set for new stations in
+                * this case.
+                */
+               if (!(params.sta_flags_mask & auth_assoc)) {
+                       params.sta_flags_mask |= auth_assoc;
+                       params.sta_flags_set |= auth_assoc;
+               }
 
                /* must be last in here for error handling */
                params.vlan = get_vlan(info, rdev);