diff options
author | Alexander Aring <aar@pengutronix.de> | 2016-06-18 04:45:34 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2016-07-08 06:20:57 -0400 |
commit | 66e5c2672cd11b9310008099faf6a4ffb9dfb6d0 (patch) | |
tree | 44fa2118c4570d457a5f4cafd33ec9fdd4bc28f3 | |
parent | aece0c3fe1f06962a591268b8c236df0ae5d9e4e (diff) |
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: Stefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: Alexander Aring <aar@pengutronix.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/cfg802154.h | 13 | ||||
-rw-r--r-- | include/net/nl802154.h | 5 | ||||
-rw-r--r-- | net/ieee802154/core.c | 70 | ||||
-rw-r--r-- | net/ieee802154/core.h | 2 | ||||
-rw-r--r-- | net/ieee802154/nl802154.c | 54 |
5 files changed, 138 insertions, 6 deletions
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 171cd76558fb..795ca4008f72 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h | |||
@@ -219,9 +219,22 @@ struct wpan_phy { | |||
219 | 219 | ||
220 | struct device dev; | 220 | struct device dev; |
221 | 221 | ||
222 | /* the network namespace this phy lives in currently */ | ||
223 | possible_net_t _net; | ||
224 | |||
222 | char priv[0] __aligned(NETDEV_ALIGN); | 225 | char priv[0] __aligned(NETDEV_ALIGN); |
223 | }; | 226 | }; |
224 | 227 | ||
228 | static inline struct net *wpan_phy_net(struct wpan_phy *wpan_phy) | ||
229 | { | ||
230 | return read_pnet(&wpan_phy->_net); | ||
231 | } | ||
232 | |||
233 | static inline void wpan_phy_net_set(struct wpan_phy *wpan_phy, struct net *net) | ||
234 | { | ||
235 | write_pnet(&wpan_phy->_net, net); | ||
236 | } | ||
237 | |||
225 | struct ieee802154_addr { | 238 | struct ieee802154_addr { |
226 | u8 mode; | 239 | u8 mode; |
227 | __le16 pan_id; | 240 | __le16 pan_id; |
diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 7aad2fdfd16a..ddcee128f5d9 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h | |||
@@ -54,6 +54,8 @@ enum nl802154_commands { | |||
54 | 54 | ||
55 | NL802154_CMD_SET_ACKREQ_DEFAULT, | 55 | NL802154_CMD_SET_ACKREQ_DEFAULT, |
56 | 56 | ||
57 | NL802154_CMD_SET_WPAN_PHY_NETNS, | ||
58 | |||
57 | /* add new commands above here */ | 59 | /* add new commands above here */ |
58 | 60 | ||
59 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL | 61 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL |
@@ -126,6 +128,9 @@ enum nl802154_attrs { | |||
126 | 128 | ||
127 | NL802154_ATTR_PAD, | 129 | NL802154_ATTR_PAD, |
128 | 130 | ||
131 | NL802154_ATTR_PID, | ||
132 | NL802154_ATTR_NETNS_FD, | ||
133 | |||
129 | /* add attributes here, update the policy in nl802154.c */ | 134 | /* add attributes here, update the policy in nl802154.c */ |
130 | 135 | ||
131 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL | 136 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL |
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index c35fdfa6d04e..cb7176cd4cd6 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c | |||
@@ -140,6 +140,8 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) | |||
140 | rdev->wpan_phy.dev.class = &wpan_phy_class; | 140 | rdev->wpan_phy.dev.class = &wpan_phy_class; |
141 | rdev->wpan_phy.dev.platform_data = rdev; | 141 | rdev->wpan_phy.dev.platform_data = rdev; |
142 | 142 | ||
143 | wpan_phy_net_set(&rdev->wpan_phy, &init_net); | ||
144 | |||
143 | init_waitqueue_head(&rdev->dev_wait); | 145 | init_waitqueue_head(&rdev->dev_wait); |
144 | 146 | ||
145 | return &rdev->wpan_phy; | 147 | return &rdev->wpan_phy; |
@@ -207,6 +209,49 @@ void wpan_phy_free(struct wpan_phy *phy) | |||
207 | } | 209 | } |
208 | EXPORT_SYMBOL(wpan_phy_free); | 210 | EXPORT_SYMBOL(wpan_phy_free); |
209 | 211 | ||
212 | int cfg802154_switch_netns(struct cfg802154_registered_device *rdev, | ||
213 | struct net *net) | ||
214 | { | ||
215 | struct wpan_dev *wpan_dev; | ||
216 | int err = 0; | ||
217 | |||
218 | list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { | ||
219 | if (!wpan_dev->netdev) | ||
220 | continue; | ||
221 | wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | ||
222 | err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d"); | ||
223 | if (err) | ||
224 | break; | ||
225 | wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL; | ||
226 | } | ||
227 | |||
228 | if (err) { | ||
229 | /* failed -- clean up to old netns */ | ||
230 | net = wpan_phy_net(&rdev->wpan_phy); | ||
231 | |||
232 | list_for_each_entry_continue_reverse(wpan_dev, | ||
233 | &rdev->wpan_dev_list, | ||
234 | list) { | ||
235 | if (!wpan_dev->netdev) | ||
236 | continue; | ||
237 | wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | ||
238 | err = dev_change_net_namespace(wpan_dev->netdev, net, | ||
239 | "wpan%d"); | ||
240 | WARN_ON(err); | ||
241 | wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL; | ||
242 | } | ||
243 | |||
244 | return err; | ||
245 | } | ||
246 | |||
247 | wpan_phy_net_set(&rdev->wpan_phy, net); | ||
248 | |||
249 | err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev)); | ||
250 | WARN_ON(err); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
210 | void cfg802154_dev_free(struct cfg802154_registered_device *rdev) | 255 | void cfg802154_dev_free(struct cfg802154_registered_device *rdev) |
211 | { | 256 | { |
212 | kfree(rdev); | 257 | kfree(rdev); |
@@ -286,14 +331,34 @@ static struct notifier_block cfg802154_netdev_notifier = { | |||
286 | .notifier_call = cfg802154_netdev_notifier_call, | 331 | .notifier_call = cfg802154_netdev_notifier_call, |
287 | }; | 332 | }; |
288 | 333 | ||
334 | static void __net_exit cfg802154_pernet_exit(struct net *net) | ||
335 | { | ||
336 | struct cfg802154_registered_device *rdev; | ||
337 | |||
338 | rtnl_lock(); | ||
339 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { | ||
340 | if (net_eq(wpan_phy_net(&rdev->wpan_phy), net)) | ||
341 | WARN_ON(cfg802154_switch_netns(rdev, &init_net)); | ||
342 | } | ||
343 | rtnl_unlock(); | ||
344 | } | ||
345 | |||
346 | static struct pernet_operations cfg802154_pernet_ops = { | ||
347 | .exit = cfg802154_pernet_exit, | ||
348 | }; | ||
349 | |||
289 | static int __init wpan_phy_class_init(void) | 350 | static int __init wpan_phy_class_init(void) |
290 | { | 351 | { |
291 | int rc; | 352 | int rc; |
292 | 353 | ||
293 | rc = wpan_phy_sysfs_init(); | 354 | rc = register_pernet_device(&cfg802154_pernet_ops); |
294 | if (rc) | 355 | if (rc) |
295 | goto err; | 356 | goto err; |
296 | 357 | ||
358 | rc = wpan_phy_sysfs_init(); | ||
359 | if (rc) | ||
360 | goto err_sysfs; | ||
361 | |||
297 | rc = register_netdevice_notifier(&cfg802154_netdev_notifier); | 362 | rc = register_netdevice_notifier(&cfg802154_netdev_notifier); |
298 | if (rc) | 363 | if (rc) |
299 | goto err_nl; | 364 | goto err_nl; |
@@ -315,6 +380,8 @@ err_notifier: | |||
315 | unregister_netdevice_notifier(&cfg802154_netdev_notifier); | 380 | unregister_netdevice_notifier(&cfg802154_netdev_notifier); |
316 | err_nl: | 381 | err_nl: |
317 | wpan_phy_sysfs_exit(); | 382 | wpan_phy_sysfs_exit(); |
383 | err_sysfs: | ||
384 | unregister_pernet_device(&cfg802154_pernet_ops); | ||
318 | err: | 385 | err: |
319 | return rc; | 386 | return rc; |
320 | } | 387 | } |
@@ -326,6 +393,7 @@ static void __exit wpan_phy_class_exit(void) | |||
326 | ieee802154_nl_exit(); | 393 | ieee802154_nl_exit(); |
327 | unregister_netdevice_notifier(&cfg802154_netdev_notifier); | 394 | unregister_netdevice_notifier(&cfg802154_netdev_notifier); |
328 | wpan_phy_sysfs_exit(); | 395 | wpan_phy_sysfs_exit(); |
396 | unregister_pernet_device(&cfg802154_pernet_ops); | ||
329 | } | 397 | } |
330 | module_exit(wpan_phy_class_exit); | 398 | module_exit(wpan_phy_class_exit); |
331 | 399 | ||
diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index 231fade959f3..81141f58d079 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h | |||
@@ -38,6 +38,8 @@ wpan_phy_to_rdev(struct wpan_phy *wpan_phy) | |||
38 | extern struct list_head cfg802154_rdev_list; | 38 | extern struct list_head cfg802154_rdev_list; |
39 | extern int cfg802154_rdev_list_generation; | 39 | extern int cfg802154_rdev_list_generation; |
40 | 40 | ||
41 | int cfg802154_switch_netns(struct cfg802154_registered_device *rdev, | ||
42 | struct net *net); | ||
41 | /* free object */ | 43 | /* free object */ |
42 | void cfg802154_dev_free(struct cfg802154_registered_device *rdev); | 44 | void cfg802154_dev_free(struct cfg802154_registered_device *rdev); |
43 | struct cfg802154_registered_device * | 45 | struct cfg802154_registered_device * |
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 116187b5c267..d90a4ed5b8a0 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c | |||
@@ -80,7 +80,8 @@ __cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
80 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { | 80 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { |
81 | struct wpan_dev *wpan_dev; | 81 | struct wpan_dev *wpan_dev; |
82 | 82 | ||
83 | /* TODO netns compare */ | 83 | if (wpan_phy_net(&rdev->wpan_phy) != netns) |
84 | continue; | ||
84 | 85 | ||
85 | if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx) | 86 | if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx) |
86 | continue; | 87 | continue; |
@@ -175,7 +176,8 @@ __cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
175 | if (!rdev) | 176 | if (!rdev) |
176 | return ERR_PTR(-ENODEV); | 177 | return ERR_PTR(-ENODEV); |
177 | 178 | ||
178 | /* TODO netns compare */ | 179 | if (netns != wpan_phy_net(&rdev->wpan_phy)) |
180 | return ERR_PTR(-ENODEV); | ||
179 | 181 | ||
180 | return rdev; | 182 | return rdev; |
181 | } | 183 | } |
@@ -233,6 +235,8 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { | |||
233 | 235 | ||
234 | [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 }, | 236 | [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 }, |
235 | 237 | ||
238 | [NL802154_ATTR_PID] = { .type = NLA_U32 }, | ||
239 | [NL802154_ATTR_NETNS_FD] = { .type = NLA_U32 }, | ||
236 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL | 240 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL |
237 | [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, | 241 | [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, |
238 | [NL802154_ATTR_SEC_OUT_LEVEL] = { .type = NLA_U32, }, | 242 | [NL802154_ATTR_SEC_OUT_LEVEL] = { .type = NLA_U32, }, |
@@ -590,7 +594,6 @@ static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb, | |||
590 | struct cfg802154_registered_device *rdev; | 594 | struct cfg802154_registered_device *rdev; |
591 | int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]); | 595 | int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]); |
592 | 596 | ||
593 | /* TODO netns */ | ||
594 | netdev = __dev_get_by_index(&init_net, ifidx); | 597 | netdev = __dev_get_by_index(&init_net, ifidx); |
595 | if (!netdev) | 598 | if (!netdev) |
596 | return -ENODEV; | 599 | return -ENODEV; |
@@ -629,7 +632,8 @@ nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb) | |||
629 | } | 632 | } |
630 | 633 | ||
631 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { | 634 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { |
632 | /* TODO net ns compare */ | 635 | if (!net_eq(wpan_phy_net(&rdev->wpan_phy), sock_net(skb->sk))) |
636 | continue; | ||
633 | if (++idx <= state->start) | 637 | if (++idx <= state->start) |
634 | continue; | 638 | continue; |
635 | if (state->filter_wpan_phy != -1 && | 639 | if (state->filter_wpan_phy != -1 && |
@@ -871,7 +875,8 @@ nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) | |||
871 | 875 | ||
872 | rtnl_lock(); | 876 | rtnl_lock(); |
873 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { | 877 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { |
874 | /* TODO netns compare */ | 878 | if (!net_eq(wpan_phy_net(&rdev->wpan_phy), sock_net(skb->sk))) |
879 | continue; | ||
875 | if (wp_idx < wp_start) { | 880 | if (wp_idx < wp_start) { |
876 | wp_idx++; | 881 | wp_idx++; |
877 | continue; | 882 | continue; |
@@ -1271,6 +1276,37 @@ nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info) | |||
1271 | return rdev_set_ackreq_default(rdev, wpan_dev, ackreq); | 1276 | return rdev_set_ackreq_default(rdev, wpan_dev, ackreq); |
1272 | } | 1277 | } |
1273 | 1278 | ||
1279 | static int nl802154_wpan_phy_netns(struct sk_buff *skb, struct genl_info *info) | ||
1280 | { | ||
1281 | struct cfg802154_registered_device *rdev = info->user_ptr[0]; | ||
1282 | struct net *net; | ||
1283 | int err; | ||
1284 | |||
1285 | if (info->attrs[NL802154_ATTR_PID]) { | ||
1286 | u32 pid = nla_get_u32(info->attrs[NL802154_ATTR_PID]); | ||
1287 | |||
1288 | net = get_net_ns_by_pid(pid); | ||
1289 | } else if (info->attrs[NL802154_ATTR_NETNS_FD]) { | ||
1290 | u32 fd = nla_get_u32(info->attrs[NL802154_ATTR_NETNS_FD]); | ||
1291 | |||
1292 | net = get_net_ns_by_fd(fd); | ||
1293 | } else { | ||
1294 | return -EINVAL; | ||
1295 | } | ||
1296 | |||
1297 | if (IS_ERR(net)) | ||
1298 | return PTR_ERR(net); | ||
1299 | |||
1300 | err = 0; | ||
1301 | |||
1302 | /* check if anything to do */ | ||
1303 | if (!net_eq(wpan_phy_net(&rdev->wpan_phy), net)) | ||
1304 | err = cfg802154_switch_netns(rdev, net); | ||
1305 | |||
1306 | put_net(net); | ||
1307 | return err; | ||
1308 | } | ||
1309 | |||
1274 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL | 1310 | #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL |
1275 | static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { | 1311 | static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { |
1276 | [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, | 1312 | [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, |
@@ -2262,6 +2298,14 @@ static const struct genl_ops nl802154_ops[] = { | |||
2262 | NL802154_FLAG_NEED_RTNL, | 2298 | NL802154_FLAG_NEED_RTNL, |
2263 | }, | 2299 | }, |
2264 | { | 2300 | { |
2301 | .cmd = NL802154_CMD_SET_WPAN_PHY_NETNS, | ||
2302 | .doit = nl802154_wpan_phy_netns, | ||
2303 | .policy = nl802154_policy, | ||
2304 | .flags = GENL_ADMIN_PERM, | ||
2305 | .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | | ||
2306 | NL802154_FLAG_NEED_RTNL, | ||
2307 | }, | ||
2308 | { | ||
2265 | .cmd = NL802154_CMD_SET_PAN_ID, | 2309 | .cmd = NL802154_CMD_SET_PAN_ID, |
2266 | .doit = nl802154_set_pan_id, | 2310 | .doit = nl802154_set_pan_id, |
2267 | .policy = nl802154_policy, | 2311 | .policy = nl802154_policy, |