]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/wireless/nl80211.c
Merge tag 'mac80211-for-davem-2017-07-07' of git://git.kernel.org/pub/scm/linux/kerne...
[karo-tx-linux.git] / net / wireless / nl80211.c
index 571aed1e6f362594e6a7cfe5e917b577914376bd..8ce85420ecb0a7e45567c9c576c6bb9691eb267d 100644 (file)
@@ -7505,6 +7505,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
        static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
        int err;
        bool need_new_beacon = false;
+       bool need_handle_dfs_flag = true;
        int len, i;
        u32 cs_count;
 
@@ -7516,6 +7517,12 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
                need_new_beacon = true;
+               /* For all modes except AP the handle_dfs flag needs to be
+                * supplied to tell the kernel that userspace will handle radar
+                * events when they happen. Otherwise a switch to a channel
+                * requiring DFS will be rejected.
+                */
+               need_handle_dfs_flag = false;
 
                /* useless if AP is not running */
                if (!wdev->beacon_interval)
@@ -7638,8 +7645,13 @@ skip_beacons:
        if (err < 0)
                return err;
 
-       if (err > 0)
+       if (err > 0) {
                params.radar_required = true;
+               if (need_handle_dfs_flag &&
+                   !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
+                       return -EINVAL;
+               }
+       }
 
        if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
                params.block_tx = true;
@@ -8160,6 +8172,15 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
                memcpy(settings->akm_suites, data, len);
        }
 
+       if (info->attrs[NL80211_ATTR_PMK]) {
+               if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN)
+                       return -EINVAL;
+               if (!wiphy_ext_feature_isset(&rdev->wiphy,
+                                            NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
+                       return -EINVAL;
+               settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
+       }
+
        return 0;
 }
 
@@ -8864,6 +8885,12 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 
        connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
 
+       if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
+           !wiphy_ext_feature_isset(&rdev->wiphy,
+                                    NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+               return -EINVAL;
+       connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];
+
        err = nl80211_crypto_settings(rdev, info, &connect.crypto,
                                      NL80211_MAX_NR_CIPHER_SUITES);
        if (err)
@@ -9966,6 +9993,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
+       setup.userspace_handles_dfs =
+               nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
+
        return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
 }
 
@@ -11180,10 +11210,6 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
        if (!info->attrs[NL80211_ATTR_NAN_FUNC])
                return -EINVAL;
 
-       if (wdev->owner_nlportid &&
-           wdev->owner_nlportid != info->snd_portid)
-               return -ENOTCONN;
-
        err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
                               info->attrs[NL80211_ATTR_NAN_FUNC],
                               nl80211_nan_func_policy, info->extack);
@@ -11415,10 +11441,6 @@ static int nl80211_nan_del_func(struct sk_buff *skb,
        if (!info->attrs[NL80211_ATTR_COOKIE])
                return -EINVAL;
 
-       if (wdev->owner_nlportid &&
-           wdev->owner_nlportid != info->snd_portid)
-               return -ENOTCONN;
-
        cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
 
        rdev_del_nan_func(rdev, wdev, cookie);
@@ -12245,6 +12267,90 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
        return rdev_set_multicast_to_unicast(rdev, dev, enabled);
 }
 
+static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_pmk_conf pmk_conf = {};
+       int ret;
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION &&
+           wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
+
+       if (!wiphy_ext_feature_isset(&rdev->wiphy,
+                                    NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
+               return -EINVAL;
+
+       wdev_lock(wdev);
+       if (!wdev->current_bss) {
+               ret = -ENOTCONN;
+               goto out;
+       }
+
+       pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
+       pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
+       if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
+           pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (info->attrs[NL80211_ATTR_PMKR0_NAME]) {
+               int r0_name_len = nla_len(info->attrs[NL80211_ATTR_PMKR0_NAME]);
+
+               if (r0_name_len != WLAN_PMK_NAME_LEN) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               pmk_conf.pmk_r0_name =
+                       nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
+       }
+
+       ret = rdev_set_pmk(rdev, dev, &pmk_conf);
+out:
+       wdev_unlock(wdev);
+       return ret;
+}
+
+static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       const u8 *aa;
+       int ret;
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION &&
+           wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
+
+       if (!wiphy_ext_feature_isset(&rdev->wiphy,
+                                    NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       wdev_lock(wdev);
+       aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       ret = rdev_del_pmk(rdev, dev, aa);
+       wdev_unlock(wdev);
+
+       return ret;
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -13120,6 +13226,21 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_SET_PMK,
+               .doit = nl80211_set_pmk,
+               .policy = nl80211_policy,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_DEL_PMK,
+               .doit = nl80211_del_pmk,
+               .policy = nl80211_policy,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+
 };
 
 static struct genl_family nl80211_fam __ro_after_init = {
@@ -13675,7 +13796,9 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
                     info->req_ie)) ||
            (info->resp_ie &&
             nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
-                    info->resp_ie)))
+                    info->resp_ie)) ||
+           (info->authorized &&
+            nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)))
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);