Skip to content

Commit

Permalink
Merge tag 'mac80211-next-for-davem-2018-12-19' of git://git.kernel.or…
Browse files Browse the repository at this point in the history
…g/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
This time we have too many changes to list, highlights:
 * virt_wifi - wireless control simulation on top of
   another network interface
 * hwsim configurability to test capabilities similar
   to real hardware
 * various mesh improvements
 * various radiotap vendor data fixes in mac80211
 * finally the nl_set_extack_cookie_u64() we talked
   about previously, used for
 * peer measurement APIs, right now only with FTM
   (flight time measurement) for location
 * made nl80211 radio/interface announcements more complete
 * various new HE (802.11ax) things:
   updates, TWT support, ...
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 19, 2018
2 parents 33f18c9 + d359bbc commit 5a862f8
Show file tree
Hide file tree
Showing 41 changed files with 2,934 additions and 252 deletions.
7 changes: 7 additions & 0 deletions drivers/net/wireless/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,11 @@ config USB_NET_RNDIS_WLAN

If you choose to build a module, it'll be called rndis_wlan.

config VIRT_WIFI
tristate "Wifi wrapper for ethernet drivers"
depends on CFG80211
---help---
This option adds support for ethernet connections to appear as if they
are wifi connections through a special rtnetlink device.

endif # WLAN
2 changes: 2 additions & 0 deletions drivers/net/wireless/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o

obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o

obj-$(CONFIG_VIRT_WIFI) += virt_wifi.o
257 changes: 179 additions & 78 deletions drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -451,48 +465,6 @@ static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = {
{ .vendor_id = OUI_QCA, .subcmd = 1 },
};

static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) },
/* must be last, see hwsim_if_comb */
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }
};

static const struct ieee80211_iface_combination hwsim_if_comb[] = {
{
.limits = hwsim_if_limits,
/* remove the last entry which is P2P_DEVICE */
.n_limits = ARRAY_SIZE(hwsim_if_limits) - 1,
.max_interfaces = 2048,
.num_different_channels = 1,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
},
};

static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
{
.limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
},
};

static spinlock_t hwsim_radio_lock;
static LIST_HEAD(hwsim_radios);
static struct rhashtable hwsim_radios_rht;
Expand All @@ -515,6 +487,10 @@ struct mac80211_hwsim_data {
struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
struct ieee80211_iface_combination if_combination;
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;
Expand Down Expand Up @@ -642,6 +618,8 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG },
[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,
Expand Down Expand Up @@ -2414,6 +2392,9 @@ struct hwsim_new_radio_params {
const char *hwname;
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,
Expand Down Expand Up @@ -2630,6 +2611,27 @@ static void mac80211_hswim_he_capab(struct ieee80211_supported_band *sband)
sband->n_iftype_data = 1;
}

#ifdef CONFIG_MAC80211_MESH
#define HWSIM_MESH_BIT BIT(NL80211_IFTYPE_MESH_POINT)
#else
#define HWSIM_MESH_BIT 0
#endif

#define HWSIM_DEFAULT_IF_LIMIT \
(BIT(NL80211_IFTYPE_STATION) | \
BIT(NL80211_IFTYPE_P2P_CLIENT) | \
BIT(NL80211_IFTYPE_AP) | \
BIT(NL80211_IFTYPE_P2P_GO) | \
HWSIM_MESH_BIT)

#define HWSIM_IFTYPE_SUPPORT_MASK \
(BIT(NL80211_IFTYPE_STATION) | \
BIT(NL80211_IFTYPE_AP) | \
BIT(NL80211_IFTYPE_P2P_CLIENT) | \
BIT(NL80211_IFTYPE_P2P_GO) | \
BIT(NL80211_IFTYPE_ADHOC) | \
BIT(NL80211_IFTYPE_MESH_POINT))

static int mac80211_hwsim_new_radio(struct genl_info *info,
struct hwsim_new_radio_params *param)
{
Expand All @@ -2641,6 +2643,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
struct net *net;
int idx;
int n_limits = 0;

if (WARN_ON(param->channels > 1 && !param->use_chanctx))
return -EINVAL;
Expand Down Expand Up @@ -2716,26 +2719,60 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
if (info)
data->portid = info->snd_portid;

/* setup interface limits, only on interface types we support */
if (param->iftypes & BIT(NL80211_IFTYPE_ADHOC)) {
data->if_limits[n_limits].max = 1;
data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_ADHOC);
n_limits++;
}

if (param->iftypes & HWSIM_DEFAULT_IF_LIMIT) {
data->if_limits[n_limits].max = 2048;
/*
* For this case, we may only support a subset of
* HWSIM_DEFAULT_IF_LIMIT, therefore we only want to add the
* bits that both param->iftype & HWSIM_DEFAULT_IF_LIMIT have.
*/
data->if_limits[n_limits].types =
HWSIM_DEFAULT_IF_LIMIT & param->iftypes;
n_limits++;
}

if (param->iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) {
data->if_limits[n_limits].max = 1;
data->if_limits[n_limits].types =
BIT(NL80211_IFTYPE_P2P_DEVICE);
n_limits++;
}

if (data->use_chanctx) {
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->max_remain_on_channel_duration = 1000;
hw->wiphy->iface_combinations = &data->if_combination;
if (param->p2p_device)
data->if_combination = hwsim_if_comb_p2p_dev[0];
else
data->if_combination = hwsim_if_comb[0];
hw->wiphy->n_iface_combinations = 1;
/* For channels > 1 DFS is not allowed */
data->if_combination.radar_detect_widths = 0;
data->if_combination.num_different_channels = data->channels;
} else if (param->p2p_device) {
hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
hw->wiphy->n_iface_combinations =
ARRAY_SIZE(hwsim_if_comb_p2p_dev);
} else {
hw->wiphy->iface_combinations = hwsim_if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
data->if_combination.num_different_channels = 1;
data->if_combination.radar_detect_widths =
BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160);
}

data->if_combination.n_limits = n_limits;
data->if_combination.max_interfaces = 2048;
data->if_combination.limits = data->if_limits;

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);
Expand All @@ -2744,15 +2781,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,

hw->queues = 5;
hw->offchannel_tx_hw_queue = 4;
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);

if (param->p2p_device)
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);

ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
Expand All @@ -2778,6 +2806,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);

hw->wiphy->interface_modes = param->iftypes;

/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
hw->sta_data_size = sizeof(struct hwsim_sta_priv);
Expand Down Expand Up @@ -3293,6 +3323,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 };
Expand Down Expand Up @@ -3321,15 +3374,6 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
if (info->attrs[HWSIM_ATTR_NO_VIF])
param.no_vif = true;

if (info->attrs[HWSIM_ATTR_RADIO_NAME]) {
hwname = kasprintf(GFP_KERNEL, "%.*s",
nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]),
(char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]));
if (!hwname)
return -ENOMEM;
param.hwname = hwname;
}

if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
param.use_chanctx = true;
else
Expand All @@ -3342,10 +3386,8 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);

if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) {
kfree(hwname);
if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
return -EINVAL;
}

idx = array_index_nospec(idx,
ARRAY_SIZE(hwsim_world_regdom_custom));
Expand All @@ -3358,14 +3400,72 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
GENL_SET_ERR_MSG(info,"MAC is no valid source addr");
NL_SET_BAD_ATTR(info->extack,
info->attrs[HWSIM_ATTR_PERM_ADDR]);
kfree(hwname);
return -EINVAL;
}


param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]);
}

if (info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]) {
param.iftypes =
nla_get_u32(info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]);

if (param.iftypes & ~HWSIM_IFTYPE_SUPPORT_MASK) {
NL_SET_ERR_MSG_ATTR(info->extack,
info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT],
"cannot support more iftypes than kernel");
return -EINVAL;
}
} else {
param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK;
}

/* ensure both flag and iftype support is honored */
if (param.p2p_device ||
param.iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) {
param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
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]),
(char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]));
if (!hwname)
return -ENOMEM;
param.hwname = hwname;
}

ret = mac80211_hwsim_new_radio(info, &param);
kfree(hwname);
return ret;
Expand Down Expand Up @@ -3785,6 +3885,7 @@ static int __init init_mac80211_hwsim(void)

param.p2p_device = support_p2p_device;
param.use_chanctx = channels > 1;
param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK;

err = mac80211_hwsim_new_radio(NULL, &param);
if (err < 0)
Expand Down
Loading

0 comments on commit 5a862f8

Please sign in to comment.