},
        [NL80211_IFTYPE_STATION] = {
                .tx = 0xffff,
+               /*
+                * To support Pre Association Security Negotiation (PASN) while
+                * already associated to one AP, allow user space to register to
+                * Rx authentication frames, so that the user space logic would
+                * be able to receive/handle authentication frames from a
+                * different AP as part of PASN.
+                * It is expected that user space would intelligently register
+                * for Rx authentication frames, i.e., only when PASN is used
+                * and configure a match filter only for PASN authentication
+                * algorithm, as otherwise the MLME functionality of mac80211
+                * would be broken.
+                */
                .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
                        BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
        },
        [NL80211_IFTYPE_AP] = {
 
                        struct net_device *dev);
 int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
                                u16 frame_type, const u8 *match_data,
-                               int match_len);
+                               int match_len, struct netlink_ext_ack *extack);
 void cfg80211_mlme_unreg_wk(struct work_struct *wk);
 void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
 
  *
  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2015          Intel Deutschland GmbH
+ * Copyright (C) 2019 Intel Corporation
  */
 
 #include <linux/kernel.h>
 
 int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
                                u16 frame_type, const u8 *match_data,
-                               int match_len)
+                               int match_len, struct netlink_ext_ack *extack)
 {
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        if (!wdev->wiphy->mgmt_stypes)
                return -EOPNOTSUPP;
 
-       if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
+       if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) {
+               NL_SET_ERR_MSG(extack, "frame type not management");
                return -EINVAL;
+       }
 
-       if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
+       if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) {
+               NL_SET_ERR_MSG(extack, "Invalid frame type");
                return -EINVAL;
+       }
 
        mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
-       if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type)))
+       if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) {
+               NL_SET_ERR_MSG(extack,
+                              "Registration to specific type not supported");
+               return -EINVAL;
+       }
+
+       /*
+        * To support Pre Association Security Negotiation (PASN), registration
+        * for authentication frames should be supported. However, as some
+        * versions of the user space daemons wrongly register to all types of
+        * authentication frames (which might result in unexpected behavior)
+        * allow such registration if the request is for a specific
+        * authentication algorithm number.
+        */
+       if (wdev->iftype == NL80211_IFTYPE_STATION &&
+           (frame_type & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_AUTH &&
+           !(match_data && match_len >= 2)) {
+               NL_SET_ERR_MSG(extack,
+                              "Authentication algorithm number required");
                return -EINVAL;
+       }
 
        nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
        if (!nreg)
                        continue;
 
                if (memcmp(reg->match, match_data, mlen) == 0) {
+                       NL_SET_ERR_MSG(extack, "Match already configured");
                        err = -EALREADY;
                        break;
                }
 
                return -EOPNOTSUPP;
 
        return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
-                       nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
-                       nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
+                                          nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
+                                          nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]),
+                                          info->extack);
 }
 
 static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)