summaryrefslogtreecommitdiffstats
path: root/net/can
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2017-04-25 02:19:43 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2017-04-25 03:04:30 -0400
commit1ef83310b81551079af992c4cbb5e089dd1397be (patch)
treed2d39af10ced10c0afc7a4057c30ccc603468626 /net/can
parent384317ef4187f59a1cb7a6163444d757340b3bb4 (diff)
can: network namespace support for CAN gateway
The CAN gateway was not implemented as per-net in the initial network namespace support by Mario Kicherer (8e8cda6d737d). This patch enables the CAN gateway to be used in different namespaces. Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'net/can')
-rw-r--r--net/can/gw.c72
1 files changed, 44 insertions, 28 deletions
diff --git a/net/can/gw.c b/net/can/gw.c
index ad5bf5d508d3..29748d844c3f 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * gw.c - CAN frame Gateway/Router/Bridge with netlink interface 2 * gw.c - CAN frame Gateway/Router/Bridge with netlink interface
3 * 3 *
4 * Copyright (c) 2011 Volkswagen Group Electronic Research 4 * Copyright (c) 2017 Volkswagen Group Electronic Research
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,7 @@
59#include <net/net_namespace.h> 59#include <net/net_namespace.h>
60#include <net/sock.h> 60#include <net/sock.h>
61 61
62#define CAN_GW_VERSION "20130117" 62#define CAN_GW_VERSION "20170425"
63#define CAN_GW_NAME "can-gw" 63#define CAN_GW_NAME "can-gw"
64 64
65MODULE_DESCRIPTION("PF_CAN netlink gateway"); 65MODULE_DESCRIPTION("PF_CAN netlink gateway");
@@ -79,9 +79,7 @@ MODULE_PARM_DESC(max_hops,
79 __stringify(CGW_MAX_HOPS) " hops, " 79 __stringify(CGW_MAX_HOPS) " hops, "
80 "default: " __stringify(CGW_DEFAULT_HOPS) ")"); 80 "default: " __stringify(CGW_DEFAULT_HOPS) ")");
81 81
82static HLIST_HEAD(cgw_list);
83static struct notifier_block notifier; 82static struct notifier_block notifier;
84
85static struct kmem_cache *cgw_cache __read_mostly; 83static struct kmem_cache *cgw_cache __read_mostly;
86 84
87/* structure that contains the (on-the-fly) CAN frame modifications */ 85/* structure that contains the (on-the-fly) CAN frame modifications */
@@ -438,16 +436,16 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
438 gwj->handled_frames++; 436 gwj->handled_frames++;
439} 437}
440 438
441static inline int cgw_register_filter(struct cgw_job *gwj) 439static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
442{ 440{
443 return can_rx_register(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id, 441 return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id,
444 gwj->ccgw.filter.can_mask, can_can_gw_rcv, 442 gwj->ccgw.filter.can_mask, can_can_gw_rcv,
445 gwj, "gw", NULL); 443 gwj, "gw", NULL);
446} 444}
447 445
448static inline void cgw_unregister_filter(struct cgw_job *gwj) 446static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj)
449{ 447{
450 can_rx_unregister(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id, 448 can_rx_unregister(net, gwj->src.dev, gwj->ccgw.filter.can_id,
451 gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj); 449 gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj);
452} 450}
453 451
@@ -455,9 +453,8 @@ static int cgw_notifier(struct notifier_block *nb,
455 unsigned long msg, void *ptr) 453 unsigned long msg, void *ptr)
456{ 454{
457 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 455 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
456 struct net *net = dev_net(dev);
458 457
459 if (!net_eq(dev_net(dev), &init_net))
460 return NOTIFY_DONE;
461 if (dev->type != ARPHRD_CAN) 458 if (dev->type != ARPHRD_CAN)
462 return NOTIFY_DONE; 459 return NOTIFY_DONE;
463 460
@@ -468,11 +465,11 @@ static int cgw_notifier(struct notifier_block *nb,
468 465
469 ASSERT_RTNL(); 466 ASSERT_RTNL();
470 467
471 hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) { 468 hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
472 469
473 if (gwj->src.dev == dev || gwj->dst.dev == dev) { 470 if (gwj->src.dev == dev || gwj->dst.dev == dev) {
474 hlist_del(&gwj->list); 471 hlist_del(&gwj->list);
475 cgw_unregister_filter(gwj); 472 cgw_unregister_filter(net, gwj);
476 kmem_cache_free(cgw_cache, gwj); 473 kmem_cache_free(cgw_cache, gwj);
477 } 474 }
478 } 475 }
@@ -592,12 +589,13 @@ cancel:
592/* Dump information about all CAN gateway jobs, in response to RTM_GETROUTE */ 589/* Dump information about all CAN gateway jobs, in response to RTM_GETROUTE */
593static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb) 590static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
594{ 591{
592 struct net *net = sock_net(skb->sk);
595 struct cgw_job *gwj = NULL; 593 struct cgw_job *gwj = NULL;
596 int idx = 0; 594 int idx = 0;
597 int s_idx = cb->args[0]; 595 int s_idx = cb->args[0];
598 596
599 rcu_read_lock(); 597 rcu_read_lock();
600 hlist_for_each_entry_rcu(gwj, &cgw_list, list) { 598 hlist_for_each_entry_rcu(gwj, &net->can.cgw_list, list) {
601 if (idx < s_idx) 599 if (idx < s_idx)
602 goto cont; 600 goto cont;
603 601
@@ -812,6 +810,7 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
812static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, 810static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
813 struct netlink_ext_ack *extack) 811 struct netlink_ext_ack *extack)
814{ 812{
813 struct net *net = sock_net(skb->sk);
815 struct rtcanmsg *r; 814 struct rtcanmsg *r;
816 struct cgw_job *gwj; 815 struct cgw_job *gwj;
817 struct cf_mod mod; 816 struct cf_mod mod;
@@ -842,7 +841,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
842 ASSERT_RTNL(); 841 ASSERT_RTNL();
843 842
844 /* check for updating an existing job with identical uid */ 843 /* check for updating an existing job with identical uid */
845 hlist_for_each_entry(gwj, &cgw_list, list) { 844 hlist_for_each_entry(gwj, &net->can.cgw_list, list) {
846 845
847 if (gwj->mod.uid != mod.uid) 846 if (gwj->mod.uid != mod.uid)
848 continue; 847 continue;
@@ -880,7 +879,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
880 879
881 err = -ENODEV; 880 err = -ENODEV;
882 881
883 gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx); 882 gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx);
884 883
885 if (!gwj->src.dev) 884 if (!gwj->src.dev)
886 goto out; 885 goto out;
@@ -888,7 +887,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
888 if (gwj->src.dev->type != ARPHRD_CAN) 887 if (gwj->src.dev->type != ARPHRD_CAN)
889 goto out; 888 goto out;
890 889
891 gwj->dst.dev = __dev_get_by_index(&init_net, gwj->ccgw.dst_idx); 890 gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx);
892 891
893 if (!gwj->dst.dev) 892 if (!gwj->dst.dev)
894 goto out; 893 goto out;
@@ -898,9 +897,9 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
898 897
899 ASSERT_RTNL(); 898 ASSERT_RTNL();
900 899
901 err = cgw_register_filter(gwj); 900 err = cgw_register_filter(net, gwj);
902 if (!err) 901 if (!err)
903 hlist_add_head_rcu(&gwj->list, &cgw_list); 902 hlist_add_head_rcu(&gwj->list, &net->can.cgw_list);
904out: 903out:
905 if (err) 904 if (err)
906 kmem_cache_free(cgw_cache, gwj); 905 kmem_cache_free(cgw_cache, gwj);
@@ -908,16 +907,16 @@ out:
908 return err; 907 return err;
909} 908}
910 909
911static void cgw_remove_all_jobs(void) 910static void cgw_remove_all_jobs(struct net *net)
912{ 911{
913 struct cgw_job *gwj = NULL; 912 struct cgw_job *gwj = NULL;
914 struct hlist_node *nx; 913 struct hlist_node *nx;
915 914
916 ASSERT_RTNL(); 915 ASSERT_RTNL();
917 916
918 hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) { 917 hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
919 hlist_del(&gwj->list); 918 hlist_del(&gwj->list);
920 cgw_unregister_filter(gwj); 919 cgw_unregister_filter(net, gwj);
921 kmem_cache_free(cgw_cache, gwj); 920 kmem_cache_free(cgw_cache, gwj);
922 } 921 }
923} 922}
@@ -925,6 +924,7 @@ static void cgw_remove_all_jobs(void)
925static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, 924static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
926 struct netlink_ext_ack *extack) 925 struct netlink_ext_ack *extack)
927{ 926{
927 struct net *net = sock_net(skb->sk);
928 struct cgw_job *gwj = NULL; 928 struct cgw_job *gwj = NULL;
929 struct hlist_node *nx; 929 struct hlist_node *nx;
930 struct rtcanmsg *r; 930 struct rtcanmsg *r;
@@ -953,7 +953,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
953 953
954 /* two interface indices both set to 0 => remove all entries */ 954 /* two interface indices both set to 0 => remove all entries */
955 if (!ccgw.src_idx && !ccgw.dst_idx) { 955 if (!ccgw.src_idx && !ccgw.dst_idx) {
956 cgw_remove_all_jobs(); 956 cgw_remove_all_jobs(net);
957 return 0; 957 return 0;
958 } 958 }
959 959
@@ -962,7 +962,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
962 ASSERT_RTNL(); 962 ASSERT_RTNL();
963 963
964 /* remove only the first matching entry */ 964 /* remove only the first matching entry */
965 hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) { 965 hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
966 966
967 if (gwj->flags != r->flags) 967 if (gwj->flags != r->flags)
968 continue; 968 continue;
@@ -985,7 +985,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
985 continue; 985 continue;
986 986
987 hlist_del(&gwj->list); 987 hlist_del(&gwj->list);
988 cgw_unregister_filter(gwj); 988 cgw_unregister_filter(net, gwj);
989 kmem_cache_free(cgw_cache, gwj); 989 kmem_cache_free(cgw_cache, gwj);
990 err = 0; 990 err = 0;
991 break; 991 break;
@@ -994,6 +994,24 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
994 return err; 994 return err;
995} 995}
996 996
997static int __net_init cangw_pernet_init(struct net *net)
998{
999 INIT_HLIST_HEAD(&net->can.cgw_list);
1000 return 0;
1001}
1002
1003static void __net_exit cangw_pernet_exit(struct net *net)
1004{
1005 rtnl_lock();
1006 cgw_remove_all_jobs(net);
1007 rtnl_unlock();
1008}
1009
1010static struct pernet_operations cangw_pernet_ops = {
1011 .init = cangw_pernet_init,
1012 .exit = cangw_pernet_exit,
1013};
1014
997static __init int cgw_module_init(void) 1015static __init int cgw_module_init(void)
998{ 1016{
999 /* sanitize given module parameter */ 1017 /* sanitize given module parameter */
@@ -1002,6 +1020,7 @@ static __init int cgw_module_init(void)
1002 pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n", 1020 pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
1003 max_hops); 1021 max_hops);
1004 1022
1023 register_pernet_subsys(&cangw_pernet_ops);
1005 cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job), 1024 cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
1006 0, 0, NULL); 1025 0, 0, NULL);
1007 1026
@@ -1031,10 +1050,7 @@ static __exit void cgw_module_exit(void)
1031 1050
1032 unregister_netdevice_notifier(&notifier); 1051 unregister_netdevice_notifier(&notifier);
1033 1052
1034 rtnl_lock(); 1053 unregister_pernet_subsys(&cangw_pernet_ops);
1035 cgw_remove_all_jobs();
1036 rtnl_unlock();
1037
1038 rcu_barrier(); /* Wait for completion of call_rcu()'s */ 1054 rcu_barrier(); /* Wait for completion of call_rcu()'s */
1039 1055
1040 kmem_cache_destroy(cgw_cache); 1056 kmem_cache_destroy(cgw_cache);