Skip to content

Commit 100cb9f

Browse files
martinwillijmberg-intel
authored andcommitted
mac80211_hwsim: Allow managing radios from non-initial namespaces
While wiphys can be moved into network namespaces over nl80211, the creation and removal of hwsim radios is currently limited to the initial namespace. This patch allows management of namespaced radios from the owning namespace by setting genetlink netnsok. To prevent two arbitrary namespaces to communicate over the simulated shared medium, radios are separated by netgroups. Each radio created in the same namespace lives in the same netgroup and hence can communicate with other radios in that group. When moving radios to other namespaces, the netgroup is preserved, so two radios having the same netgroup can communicate even if not in the same namespace; This allows a controlling namespace to create radios and move them to other namespaces for communication. When a net namespace owning a radio exits, the radio is destroyed unless it was created in the initial network namespace. This keeps the previous behavior by returning them to the init namespace, but prevents unprivileged users from creating radios in the initial namespace. Signed-off-by: Martin Willi <martin@strongswan.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 5617c6c commit 100cb9f

File tree

1 file changed

+94
-3
lines changed

1 file changed

+94
-3
lines changed

drivers/net/wireless/mac80211_hwsim.c

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include <linux/module.h>
3131
#include <linux/ktime.h>
3232
#include <net/genetlink.h>
33+
#include <net/net_namespace.h>
34+
#include <net/netns/generic.h>
3335
#include "mac80211_hwsim.h"
3436

3537
#define WARN_QUEUE 100
@@ -250,6 +252,28 @@ static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c)
250252
cp->magic = 0;
251253
}
252254

255+
static unsigned int hwsim_net_id;
256+
257+
static int hwsim_netgroup;
258+
259+
struct hwsim_net {
260+
int netgroup;
261+
};
262+
263+
static inline int hwsim_net_get_netgroup(struct net *net)
264+
{
265+
struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
266+
267+
return hwsim_net->netgroup;
268+
}
269+
270+
static inline void hwsim_net_set_netgroup(struct net *net)
271+
{
272+
struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
273+
274+
hwsim_net->netgroup = hwsim_netgroup++;
275+
}
276+
253277
static struct class *hwsim_class;
254278

255279
static struct net_device *hwsim_mon; /* global monitor netdev */
@@ -526,6 +550,9 @@ struct mac80211_hwsim_data {
526550
*/
527551
u64 group;
528552

553+
/* group shared by radios created in the same netns */
554+
int netgroup;
555+
529556
int power_level;
530557

531558
/* difference between this hw's clock and the real clock, in usecs */
@@ -568,6 +595,7 @@ static struct genl_family hwsim_genl_family = {
568595
.name = "MAC80211_HWSIM",
569596
.version = 1,
570597
.maxattr = HWSIM_ATTR_MAX,
598+
.netnsok = true,
571599
};
572600

573601
enum hwsim_multicast_groups {
@@ -1202,6 +1230,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
12021230
if (!(data->group & data2->group))
12031231
continue;
12041232

1233+
if (data->netgroup != data2->netgroup)
1234+
continue;
1235+
12051236
if (!hwsim_chans_compat(chan, data2->tmp_chan) &&
12061237
!hwsim_chans_compat(chan, data2->channel)) {
12071238
ieee80211_iterate_active_interfaces_atomic(
@@ -2349,6 +2380,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
23492380
struct ieee80211_hw *hw;
23502381
enum nl80211_band band;
23512382
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
2383+
struct net *net;
23522384
int idx;
23532385

23542386
if (WARN_ON(param->channels > 1 && !param->use_chanctx))
@@ -2366,6 +2398,13 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
23662398
err = -ENOMEM;
23672399
goto failed;
23682400
}
2401+
2402+
if (info)
2403+
net = genl_info_net(info);
2404+
else
2405+
net = &init_net;
2406+
wiphy_net_set(hw->wiphy, net);
2407+
23692408
data = hw->priv;
23702409
data->hw = hw;
23712410

@@ -2541,6 +2580,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
25412580
data->group = 1;
25422581
mutex_init(&data->mutex);
25432582

2583+
data->netgroup = hwsim_net_get_netgroup(net);
2584+
25442585
/* Enable frame retransmissions for lossy channels */
25452586
hw->max_rates = 4;
25462587
hw->max_rate_tries = 11;
@@ -3013,6 +3054,9 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
30133054
continue;
30143055
}
30153056

3057+
if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info)))
3058+
continue;
3059+
30163060
list_del(&data->list);
30173061
spin_unlock_bh(&hwsim_radio_lock);
30183062
mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
@@ -3039,6 +3083,9 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
30393083
if (data->idx != idx)
30403084
continue;
30413085

3086+
if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info)))
3087+
continue;
3088+
30423089
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
30433090
if (!skb) {
30443091
res = -ENOMEM;
@@ -3078,6 +3125,9 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb,
30783125
if (data->idx < idx)
30793126
continue;
30803127

3128+
if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk)))
3129+
continue;
3130+
30813131
res = mac80211_hwsim_get_radio(skb, data,
30823132
NETLINK_CB(cb->skb).portid,
30833133
cb->nlh->nlmsg_seq, cb,
@@ -3117,13 +3167,13 @@ static const struct genl_ops hwsim_ops[] = {
31173167
.cmd = HWSIM_CMD_NEW_RADIO,
31183168
.policy = hwsim_genl_policy,
31193169
.doit = hwsim_new_radio_nl,
3120-
.flags = GENL_ADMIN_PERM,
3170+
.flags = GENL_UNS_ADMIN_PERM,
31213171
},
31223172
{
31233173
.cmd = HWSIM_CMD_DEL_RADIO,
31243174
.policy = hwsim_genl_policy,
31253175
.doit = hwsim_del_radio_nl,
3126-
.flags = GENL_ADMIN_PERM,
3176+
.flags = GENL_UNS_ADMIN_PERM,
31273177
},
31283178
{
31293179
.cmd = HWSIM_CMD_GET_RADIO,
@@ -3205,6 +3255,40 @@ static int hwsim_init_netlink(void)
32053255
return -EINVAL;
32063256
}
32073257

3258+
static __net_init int hwsim_init_net(struct net *net)
3259+
{
3260+
hwsim_net_set_netgroup(net);
3261+
3262+
return 0;
3263+
}
3264+
3265+
static void __net_exit hwsim_exit_net(struct net *net)
3266+
{
3267+
struct mac80211_hwsim_data *data, *tmp;
3268+
3269+
spin_lock_bh(&hwsim_radio_lock);
3270+
list_for_each_entry_safe(data, tmp, &hwsim_radios, list) {
3271+
if (!net_eq(wiphy_net(data->hw->wiphy), net))
3272+
continue;
3273+
3274+
/* Radios created in init_net are returned to init_net. */
3275+
if (data->netgroup == hwsim_net_get_netgroup(&init_net))
3276+
continue;
3277+
3278+
list_del(&data->list);
3279+
INIT_WORK(&data->destroy_work, destroy_radio);
3280+
schedule_work(&data->destroy_work);
3281+
}
3282+
spin_unlock_bh(&hwsim_radio_lock);
3283+
}
3284+
3285+
static struct pernet_operations hwsim_net_ops = {
3286+
.init = hwsim_init_net,
3287+
.exit = hwsim_exit_net,
3288+
.id = &hwsim_net_id,
3289+
.size = sizeof(struct hwsim_net),
3290+
};
3291+
32083292
static void hwsim_exit_netlink(void)
32093293
{
32103294
/* unregister the notifier */
@@ -3241,10 +3325,14 @@ static int __init init_mac80211_hwsim(void)
32413325
spin_lock_init(&hwsim_radio_lock);
32423326
INIT_LIST_HEAD(&hwsim_radios);
32433327

3244-
err = platform_driver_register(&mac80211_hwsim_driver);
3328+
err = register_pernet_device(&hwsim_net_ops);
32453329
if (err)
32463330
return err;
32473331

3332+
err = platform_driver_register(&mac80211_hwsim_driver);
3333+
if (err)
3334+
goto out_unregister_pernet;
3335+
32483336
hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
32493337
if (IS_ERR(hwsim_class)) {
32503338
err = PTR_ERR(hwsim_class);
@@ -3362,6 +3450,8 @@ static int __init init_mac80211_hwsim(void)
33623450
mac80211_hwsim_free();
33633451
out_unregister_driver:
33643452
platform_driver_unregister(&mac80211_hwsim_driver);
3453+
out_unregister_pernet:
3454+
unregister_pernet_device(&hwsim_net_ops);
33653455
return err;
33663456
}
33673457
module_init(init_mac80211_hwsim);
@@ -3375,5 +3465,6 @@ static void __exit exit_mac80211_hwsim(void)
33753465
mac80211_hwsim_free();
33763466
unregister_netdev(hwsim_mon);
33773467
platform_driver_unregister(&mac80211_hwsim_driver);
3468+
unregister_pernet_device(&hwsim_net_ops);
33783469
}
33793470
module_exit(exit_mac80211_hwsim);

0 commit comments

Comments
 (0)