OSDN Git Service

mac80211_hwsim: allow configurable cipher types
authorJames Prestwood <james.prestwood@linux.intel.com>
Wed, 17 Oct 2018 21:16:24 +0000 (14:16 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 9 Nov 2018 10:36:15 +0000 (11:36 +0100)
The mac80211_hwsim driver does not specify supported cipher types, which
in turn enables all ciphers to be supported in software. (see
net/mac80211/main.c:ieee80211_init_cipher_suites). Allowing ciphers
to be configurable is valuable for simulating older drivers that may
not support all ciphers.

This patch adds a new attribute:

 - HWSIM_ATTR_CIPHER_SUPPORT
A u32 array/list of supported cipher types

This only allows enabling/disabling cipher types listed in the (new)
"hwsim_ciphers" array in mac80211_hwsim.c. Any unknown cipher type
will result in -EINVAL.

Signed-off-by: James Prestwood <james.prestwood@linux.intel.com>
[fix some indentation, change to hwsim_known_ciphers(),
 add error messages, validate length better]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h

index 2fbea02..4033a80 100644 (file)
@@ -374,6 +374,20 @@ static const struct ieee80211_rate hwsim_rates[] = {
        { .bitrate = 540 }
 };
 
+static const u32 hwsim_ciphers[] = {
+       WLAN_CIPHER_SUITE_WEP40,
+       WLAN_CIPHER_SUITE_WEP104,
+       WLAN_CIPHER_SUITE_TKIP,
+       WLAN_CIPHER_SUITE_CCMP,
+       WLAN_CIPHER_SUITE_CCMP_256,
+       WLAN_CIPHER_SUITE_GCMP,
+       WLAN_CIPHER_SUITE_GCMP_256,
+       WLAN_CIPHER_SUITE_AES_CMAC,
+       WLAN_CIPHER_SUITE_BIP_CMAC_256,
+       WLAN_CIPHER_SUITE_BIP_GMAC_128,
+       WLAN_CIPHER_SUITE_BIP_GMAC_256,
+};
+
 #define OUI_QCA 0x001374
 #define QCA_NL80211_SUBCMD_TEST 1
 enum qca_nl80211_vendor_subcmds {
@@ -476,6 +490,8 @@ struct mac80211_hwsim_data {
        struct ieee80211_iface_limit if_limits[3];
        int n_if_limits;
 
+       u32 ciphers[ARRAY_SIZE(hwsim_ciphers)];
+
        struct mac_address addresses[2];
        int channels, idx;
        bool use_chanctx;
@@ -603,6 +619,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
        [HWSIM_ATTR_FREQ] = { .type = NLA_U32 },
        [HWSIM_ATTR_PERM_ADDR] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
        [HWSIM_ATTR_IFTYPE_SUPPORT] = { .type = NLA_U32 },
+       [HWSIM_ATTR_CIPHER_SUPPORT] = { .type = NLA_BINARY },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -2376,6 +2393,8 @@ struct hwsim_new_radio_params {
        bool no_vif;
        const u8 *perm_addr;
        u32 iftypes;
+       u32 *ciphers;
+       u8 n_ciphers;
 };
 
 static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
@@ -2748,6 +2767,13 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
        hw->wiphy->iface_combinations = &data->if_combination;
        hw->wiphy->n_iface_combinations = 1;
 
+       if (param->ciphers) {
+               memcpy(data->ciphers, param->ciphers,
+                      param->n_ciphers * sizeof(u32));
+               hw->wiphy->cipher_suites = data->ciphers;
+               hw->wiphy->n_cipher_suites = param->n_ciphers;
+       }
+
        INIT_DELAYED_WORK(&data->roc_start, hw_roc_start);
        INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
        INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
@@ -3296,6 +3322,29 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
        return 0;
 }
 
+/* ensures ciphers only include ciphers listed in 'hwsim_ciphers' array */
+static bool hwsim_known_ciphers(const u32 *ciphers, int n_ciphers)
+{
+       int i;
+
+       for (i = 0; i < n_ciphers; i++) {
+               int j;
+               int found = 0;
+
+               for (j = 0; j < ARRAY_SIZE(hwsim_ciphers); j++) {
+                       if (ciphers[i] == hwsim_ciphers[j]) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       return false;
+       }
+
+       return true;
+}
+
 static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
        struct hwsim_new_radio_params param = { 0 };
@@ -3377,6 +3426,36 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
                param.p2p_device = true;
        }
 
+       if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) {
+               u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]);
+
+               param.ciphers =
+                       nla_data(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]);
+
+               if (len % sizeof(u32)) {
+                       NL_SET_ERR_MSG_ATTR(info->extack,
+                                           info->attrs[HWSIM_ATTR_CIPHER_SUPPORT],
+                                           "bad cipher list length");
+                       return -EINVAL;
+               }
+
+               param.n_ciphers = len / sizeof(u32);
+
+               if (param.n_ciphers > ARRAY_SIZE(hwsim_ciphers)) {
+                       NL_SET_ERR_MSG_ATTR(info->extack,
+                                           info->attrs[HWSIM_ATTR_CIPHER_SUPPORT],
+                                           "too many ciphers specified");
+                       return -EINVAL;
+               }
+
+               if (!hwsim_known_ciphers(param.ciphers, param.n_ciphers)) {
+                       NL_SET_ERR_MSG_ATTR(info->extack,
+                                           info->attrs[HWSIM_ATTR_CIPHER_SUPPORT],
+                                           "unsupported ciphers specified");
+                       return -EINVAL;
+               }
+       }
+
        if (info->attrs[HWSIM_ATTR_RADIO_NAME]) {
                hwname = kasprintf(GFP_KERNEL, "%.*s",
                                   nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]),
index 3f6b670..a1ef845 100644 (file)
@@ -133,6 +133,7 @@ enum {
  *     rates of %HWSIM_ATTR_TX_INFO
  * @HWSIM_ATTR_PERM_ADDR: permanent mac address of new radio
  * @HWSIM_ATTR_IFTYPE_SUPPORT: u32 attribute of supported interface types bits
+ * @HWSIM_ATTR_CIPHER_SUPPORT: u32 array of supported cipher types
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -162,6 +163,7 @@ enum {
        HWSIM_ATTR_TX_INFO_FLAGS,
        HWSIM_ATTR_PERM_ADDR,
        HWSIM_ATTR_IFTYPE_SUPPORT,
+       HWSIM_ATTR_CIPHER_SUPPORT,
        __HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)