*     auth and assoc steps. For this, you need to specify the SSID in a
  *     %NL80211_ATTR_SSID attribute, and can optionally specify the association
  *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- *     %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ *     %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
  *     It is also sent as an event, with the BSSID and response IEs when the
  *     connection is established or failed to be established. This can be
  *     determined by the STATUS_CODE attribute.
  *     request, the driver will assume that the port is unauthorized until
  *     authorized by user space. Otherwise, port is marked authorized by
  *     default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ *     ethertype that will be used for key negotiation. It can be
+ *     specified with the associate and connect commands. If it is not
+ *     specified, the value defaults to 0x888E (PAE, 802.1X). This
+ *     attribute is also used as a flag in the wiphy information to
+ *     indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ *     ethertype frames used for key negotiation must not be encrypted.
  *
  * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
  *     We recommend using nested, driver-specific attributes within this.
        NL80211_ATTR_RX_FRAME_TYPES,
        NL80211_ATTR_FRAME_TYPE,
 
+       NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+       NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
 
  *     sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
  *     required to assume that the port is unauthorized until authorized by
  *     user space. Otherwise, port is marked authorized by default.
+ * @control_port_ethertype: the control port protocol that should be
+ *     allowed through even on unauthorized ports
+ * @control_port_no_encrypt: TRUE to prevent encryption of control port
+ *     protocol frames.
  */
 struct cfg80211_crypto_settings {
        u32 wpa_versions;
        int n_akm_suites;
        u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
        bool control_port;
+       __be16 control_port_ethertype;
+       bool control_port_no_encrypt;
 };
 
 /**
  * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
  *     on a VLAN interface)
  * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
+ * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
+ *     control port protocol ethertype. The device also honours the
+ *     control_port_no_encrypt flag.
  */
 enum wiphy_flags {
-       WIPHY_FLAG_CUSTOM_REGULATORY    = BIT(0),
-       WIPHY_FLAG_STRICT_REGULATORY    = BIT(1),
-       WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
-       WIPHY_FLAG_NETNS_OK             = BIT(3),
-       WIPHY_FLAG_PS_ON_BY_DEFAULT     = BIT(4),
-       WIPHY_FLAG_4ADDR_AP             = BIT(5),
-       WIPHY_FLAG_4ADDR_STATION        = BIT(6),
+       WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
+       WIPHY_FLAG_STRICT_REGULATORY            = BIT(1),
+       WIPHY_FLAG_DISABLE_BEACON_HINTS         = BIT(2),
+       WIPHY_FLAG_NETNS_OK                     = BIT(3),
+       WIPHY_FLAG_PS_ON_BY_DEFAULT             = BIT(4),
+       WIPHY_FLAG_4ADDR_AP                     = BIT(5),
+       WIPHY_FLAG_4ADDR_STATION                = BIT(6),
+       WIPHY_FLAG_CONTROL_PORT_PROTOCOL        = BIT(7),
 };
 
 struct mac_address {
 
                .len = sizeof(struct nl80211_sta_flag_update),
        },
        [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
+       [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
+       [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
        [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
        [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
        [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
        NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
                   dev->wiphy.max_num_pmkids);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE);
+
        nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
        if (!nl_modes)
                goto nla_put_failure;
        return err;
 }
 
-static int nl80211_crypto_settings(struct genl_info *info,
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+                                  struct genl_info *info,
                                   struct cfg80211_crypto_settings *settings,
                                   int cipher_limit)
 {
 
        settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
 
+       if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
+               u16 proto;
+               proto = nla_get_u16(
+                       info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+               settings->control_port_ethertype = cpu_to_be16(proto);
+               if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+                   proto != ETH_P_PAE)
+                       return -EINVAL;
+               if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
+                       settings->control_port_no_encrypt = true;
+       } else
+               settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
+
        if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
                void *data;
                int len, i;
        if (info->attrs[NL80211_ATTR_PREV_BSSID])
                prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
 
-       err = nl80211_crypto_settings(info, &crypto, 1);
+       err = nl80211_crypto_settings(rdev, info, &crypto, 1);
        if (!err)
                err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
                                          ssid, ssid_len, ie, ie_len, use_mfp,
 
        connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
 
-       err = nl80211_crypto_settings(info, &connect.crypto,
+       err = nl80211_crypto_settings(rdev, info, &connect.crypto,
                                      NL80211_MAX_NR_CIPHER_SUITES);
        if (err)
                return err;
 
        wdev->wext.connect.ssid_len = len;
 
        wdev->wext.connect.crypto.control_port = false;
+       wdev->wext.connect.crypto.control_port_ethertype =
+                                       cpu_to_be16(ETH_P_PAE);
 
        err = cfg80211_mgd_wext_connect(rdev, wdev);
  out: