Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66e5c267 authored by Alexander Aring's avatar Alexander Aring Committed by Marcel Holtmann
Browse files

ieee802154: add netns support



This patch adds netns support for 802.15.4 subsystem. Most parts are
copy&pasted from wireless subsystem, it has the identically userspace
API.

Cc: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: default avatarStefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: default avatarAlexander Aring <aar@pengutronix.de>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent aece0c3f
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -219,9 +219,22 @@ struct wpan_phy {

	struct device dev;

	/* the network namespace this phy lives in currently */
	possible_net_t _net;

	char priv[0] __aligned(NETDEV_ALIGN);
};

static inline struct net *wpan_phy_net(struct wpan_phy *wpan_phy)
{
	return read_pnet(&wpan_phy->_net);
}

static inline void wpan_phy_net_set(struct wpan_phy *wpan_phy, struct net *net)
{
	write_pnet(&wpan_phy->_net, net);
}

struct ieee802154_addr {
	u8 mode;
	__le16 pan_id;
+5 −0
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ enum nl802154_commands {

	NL802154_CMD_SET_ACKREQ_DEFAULT,

	NL802154_CMD_SET_WPAN_PHY_NETNS,

	/* add new commands above here */

#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
@@ -126,6 +128,9 @@ enum nl802154_attrs {

	NL802154_ATTR_PAD,

	NL802154_ATTR_PID,
	NL802154_ATTR_NETNS_FD,

	/* add attributes here, update the policy in nl802154.c */

#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
+69 −1
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size)
	rdev->wpan_phy.dev.class = &wpan_phy_class;
	rdev->wpan_phy.dev.platform_data = rdev;

	wpan_phy_net_set(&rdev->wpan_phy, &init_net);

	init_waitqueue_head(&rdev->dev_wait);

	return &rdev->wpan_phy;
@@ -207,6 +209,49 @@ void wpan_phy_free(struct wpan_phy *phy)
}
EXPORT_SYMBOL(wpan_phy_free);

int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
			   struct net *net)
{
	struct wpan_dev *wpan_dev;
	int err = 0;

	list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
		if (!wpan_dev->netdev)
			continue;
		wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
		err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d");
		if (err)
			break;
		wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL;
	}

	if (err) {
		/* failed -- clean up to old netns */
		net = wpan_phy_net(&rdev->wpan_phy);

		list_for_each_entry_continue_reverse(wpan_dev,
						     &rdev->wpan_dev_list,
						     list) {
			if (!wpan_dev->netdev)
				continue;
			wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
			err = dev_change_net_namespace(wpan_dev->netdev, net,
						       "wpan%d");
			WARN_ON(err);
			wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL;
		}

		return err;
	}

	wpan_phy_net_set(&rdev->wpan_phy, net);

	err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev));
	WARN_ON(err);

	return 0;
}

void cfg802154_dev_free(struct cfg802154_registered_device *rdev)
{
	kfree(rdev);
@@ -286,14 +331,34 @@ static struct notifier_block cfg802154_netdev_notifier = {
	.notifier_call = cfg802154_netdev_notifier_call,
};

static void __net_exit cfg802154_pernet_exit(struct net *net)
{
	struct cfg802154_registered_device *rdev;

	rtnl_lock();
	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
		if (net_eq(wpan_phy_net(&rdev->wpan_phy), net))
			WARN_ON(cfg802154_switch_netns(rdev, &init_net));
	}
	rtnl_unlock();
}

static struct pernet_operations cfg802154_pernet_ops = {
	.exit = cfg802154_pernet_exit,
};

static int __init wpan_phy_class_init(void)
{
	int rc;

	rc = wpan_phy_sysfs_init();
	rc = register_pernet_device(&cfg802154_pernet_ops);
	if (rc)
		goto err;

	rc = wpan_phy_sysfs_init();
	if (rc)
		goto err_sysfs;

	rc = register_netdevice_notifier(&cfg802154_netdev_notifier);
	if (rc)
		goto err_nl;
@@ -315,6 +380,8 @@ static int __init wpan_phy_class_init(void)
	unregister_netdevice_notifier(&cfg802154_netdev_notifier);
err_nl:
	wpan_phy_sysfs_exit();
err_sysfs:
	unregister_pernet_device(&cfg802154_pernet_ops);
err:
	return rc;
}
@@ -326,6 +393,7 @@ static void __exit wpan_phy_class_exit(void)
	ieee802154_nl_exit();
	unregister_netdevice_notifier(&cfg802154_netdev_notifier);
	wpan_phy_sysfs_exit();
	unregister_pernet_device(&cfg802154_pernet_ops);
}
module_exit(wpan_phy_class_exit);

+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ wpan_phy_to_rdev(struct wpan_phy *wpan_phy)
extern struct list_head cfg802154_rdev_list;
extern int cfg802154_rdev_list_generation;

int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
			   struct net *net);
/* free object */
void cfg802154_dev_free(struct cfg802154_registered_device *rdev);
struct cfg802154_registered_device *
+49 −5
Original line number Diff line number Diff line
@@ -80,7 +80,8 @@ __cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs)
	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
		struct wpan_dev *wpan_dev;

		/* TODO netns compare */
		if (wpan_phy_net(&rdev->wpan_phy) != netns)
			continue;

		if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx)
			continue;
@@ -175,7 +176,8 @@ __cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
	if (!rdev)
		return ERR_PTR(-ENODEV);

	/* TODO netns compare */
	if (netns != wpan_phy_net(&rdev->wpan_phy))
		return ERR_PTR(-ENODEV);

	return rdev;
}
@@ -233,6 +235,8 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {

	[NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 },

	[NL802154_ATTR_PID] = { .type = NLA_U32 },
	[NL802154_ATTR_NETNS_FD] = { .type = NLA_U32 },
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
	[NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
	[NL802154_ATTR_SEC_OUT_LEVEL] = { .type = NLA_U32, },
@@ -590,7 +594,6 @@ static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
		struct cfg802154_registered_device *rdev;
		int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);

		/* TODO netns */
		netdev = __dev_get_by_index(&init_net, ifidx);
		if (!netdev)
			return -ENODEV;
@@ -629,7 +632,8 @@ nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
	}

	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
		/* TODO net ns compare */
		if (!net_eq(wpan_phy_net(&rdev->wpan_phy), sock_net(skb->sk)))
			continue;
		if (++idx <= state->start)
			continue;
		if (state->filter_wpan_phy != -1 &&
@@ -871,7 +875,8 @@ nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)

	rtnl_lock();
	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
		/* TODO netns compare */
		if (!net_eq(wpan_phy_net(&rdev->wpan_phy), sock_net(skb->sk)))
			continue;
		if (wp_idx < wp_start) {
			wp_idx++;
			continue;
@@ -1271,6 +1276,37 @@ nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
	return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
}

static int nl802154_wpan_phy_netns(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg802154_registered_device *rdev = info->user_ptr[0];
	struct net *net;
	int err;

	if (info->attrs[NL802154_ATTR_PID]) {
		u32 pid = nla_get_u32(info->attrs[NL802154_ATTR_PID]);

		net = get_net_ns_by_pid(pid);
	} else if (info->attrs[NL802154_ATTR_NETNS_FD]) {
		u32 fd = nla_get_u32(info->attrs[NL802154_ATTR_NETNS_FD]);

		net = get_net_ns_by_fd(fd);
	} else {
		return -EINVAL;
	}

	if (IS_ERR(net))
		return PTR_ERR(net);

	err = 0;

	/* check if anything to do */
	if (!net_eq(wpan_phy_net(&rdev->wpan_phy), net))
		err = cfg802154_switch_netns(rdev, net);

	put_net(net);
	return err;
}

#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
	[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2261,6 +2297,14 @@ static const struct genl_ops nl802154_ops[] = {
		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
				  NL802154_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL802154_CMD_SET_WPAN_PHY_NETNS,
		.doit = nl802154_wpan_phy_netns,
		.policy = nl802154_policy,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
				  NL802154_FLAG_NEED_RTNL,
	},
	{
		.cmd = NL802154_CMD_SET_PAN_ID,
		.doit = nl802154_set_pan_id,