aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2015-06-09 02:05:10 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2015-06-09 03:39:49 -0400
commitdd895d7f21b244e7fd4c7477697e274de7e44ecb (patch)
treeb394338cd863db6e14ea822458cf84dd6cc70022
parent3d5db5e1310981ce7da570f7e686f3ff22c58b4b (diff)
can: cangw: introduce optional uid to reference created routing jobs
Similar to referencing iptables rules by their line number this UID allows to reference created routing jobs, e.g. to alter configured data modifications. The UID is an optional non-zero value which can be provided at routing job creation time. When the UID is set the UID replaces the data modification configuration as job identification attribute e.g. at job removal time. Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--include/uapi/linux/can/gw.h5
-rw-r--r--net/can/gw.c68
2 files changed, 61 insertions, 12 deletions
diff --git a/include/uapi/linux/can/gw.h b/include/uapi/linux/can/gw.h
index 3e6184cf2f6d..5079b9d57e31 100644
--- a/include/uapi/linux/can/gw.h
+++ b/include/uapi/linux/can/gw.h
@@ -78,6 +78,7 @@ enum {
78 CGW_FILTER, /* specify struct can_filter on source CAN device */ 78 CGW_FILTER, /* specify struct can_filter on source CAN device */
79 CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */ 79 CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
80 CGW_LIM_HOPS, /* limit the number of hops of this specific rule */ 80 CGW_LIM_HOPS, /* limit the number of hops of this specific rule */
81 CGW_MOD_UID, /* user defined identifier for modification updates */
81 __CGW_MAX 82 __CGW_MAX
82}; 83};
83 84
@@ -162,6 +163,10 @@ enum {
162 * load time of the can-gw module). This value is used to reduce the number of 163 * load time of the can-gw module). This value is used to reduce the number of
163 * possible hops for this gateway rule to a value smaller then max_hops. 164 * possible hops for this gateway rule to a value smaller then max_hops.
164 * 165 *
166 * CGW_MOD_UID (length 4 bytes):
167 * Optional non-zero user defined routing job identifier to alter existing
168 * modification settings at runtime.
169 *
165 * CGW_CS_XOR (length 4 bytes): 170 * CGW_CS_XOR (length 4 bytes):
166 * Set a simple XOR checksum starting with an initial value into 171 * Set a simple XOR checksum starting with an initial value into
167 * data[result-idx] using data[start-idx] .. data[end-idx] 172 * data[result-idx] using data[start-idx] .. data[end-idx]
diff --git a/net/can/gw.c b/net/can/gw.c
index a6f448e18ea8..455168718c2e 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -110,6 +110,7 @@ struct cf_mod {
110 void (*xor)(struct can_frame *cf, struct cgw_csum_xor *xor); 110 void (*xor)(struct can_frame *cf, struct cgw_csum_xor *xor);
111 void (*crc8)(struct can_frame *cf, struct cgw_csum_crc8 *crc8); 111 void (*crc8)(struct can_frame *cf, struct cgw_csum_crc8 *crc8);
112 } csumfunc; 112 } csumfunc;
113 u32 uid;
113}; 114};
114 115
115 116
@@ -548,6 +549,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
548 goto cancel; 549 goto cancel;
549 } 550 }
550 551
552 if (gwj->mod.uid) {
553 if (nla_put_u32(skb, CGW_MOD_UID, gwj->mod.uid) < 0)
554 goto cancel;
555 }
556
551 if (gwj->mod.csumfunc.crc8) { 557 if (gwj->mod.csumfunc.crc8) {
552 if (nla_put(skb, CGW_CS_CRC8, CGW_CS_CRC8_LEN, 558 if (nla_put(skb, CGW_CS_CRC8, CGW_CS_CRC8_LEN,
553 &gwj->mod.csum.crc8) < 0) 559 &gwj->mod.csum.crc8) < 0)
@@ -619,6 +625,7 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = {
619 [CGW_DST_IF] = { .type = NLA_U32 }, 625 [CGW_DST_IF] = { .type = NLA_U32 },
620 [CGW_FILTER] = { .len = sizeof(struct can_filter) }, 626 [CGW_FILTER] = { .len = sizeof(struct can_filter) },
621 [CGW_LIM_HOPS] = { .type = NLA_U8 }, 627 [CGW_LIM_HOPS] = { .type = NLA_U8 },
628 [CGW_MOD_UID] = { .type = NLA_U32 },
622}; 629};
623 630
624/* check for common and gwtype specific attributes */ 631/* check for common and gwtype specific attributes */
@@ -761,6 +768,10 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
761 else 768 else
762 mod->csumfunc.xor = cgw_csum_xor_neg; 769 mod->csumfunc.xor = cgw_csum_xor_neg;
763 } 770 }
771
772 if (tb[CGW_MOD_UID]) {
773 nla_memcpy(&mod->uid, tb[CGW_MOD_UID], sizeof(u32));
774 }
764 } 775 }
765 776
766 if (gwtype == CGW_TYPE_CAN_CAN) { 777 if (gwtype == CGW_TYPE_CAN_CAN) {
@@ -802,6 +813,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
802{ 813{
803 struct rtcanmsg *r; 814 struct rtcanmsg *r;
804 struct cgw_job *gwj; 815 struct cgw_job *gwj;
816 struct cf_mod mod;
817 struct can_can_gw ccgw;
805 u8 limhops = 0; 818 u8 limhops = 0;
806 int err = 0; 819 int err = 0;
807 820
@@ -819,6 +832,36 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
819 if (r->gwtype != CGW_TYPE_CAN_CAN) 832 if (r->gwtype != CGW_TYPE_CAN_CAN)
820 return -EINVAL; 833 return -EINVAL;
821 834
835 err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops);
836 if (err < 0)
837 return err;
838
839 if (mod.uid) {
840
841 ASSERT_RTNL();
842
843 /* check for updating an existing job with identical uid */
844 hlist_for_each_entry(gwj, &cgw_list, list) {
845
846 if (gwj->mod.uid != mod.uid)
847 continue;
848
849 /* interfaces & filters must be identical */
850 if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw)))
851 return -EINVAL;
852
853 /* update modifications with disabled softirq & quit */
854 local_bh_disable();
855 memcpy(&gwj->mod, &mod, sizeof(mod));
856 local_bh_enable();
857 return 0;
858 }
859 }
860
861 /* ifindex == 0 is not allowed for job creation */
862 if (!ccgw.src_idx || !ccgw.dst_idx)
863 return -ENODEV;
864
822 gwj = kmem_cache_alloc(cgw_cache, GFP_KERNEL); 865 gwj = kmem_cache_alloc(cgw_cache, GFP_KERNEL);
823 if (!gwj) 866 if (!gwj)
824 return -ENOMEM; 867 return -ENOMEM;
@@ -828,18 +871,14 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
828 gwj->deleted_frames = 0; 871 gwj->deleted_frames = 0;
829 gwj->flags = r->flags; 872 gwj->flags = r->flags;
830 gwj->gwtype = r->gwtype; 873 gwj->gwtype = r->gwtype;
874 gwj->limit_hops = limhops;
831 875
832 err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw, 876 /* insert already parsed information */
833 &limhops); 877 memcpy(&gwj->mod, &mod, sizeof(mod));
834 if (err < 0) 878 memcpy(&gwj->ccgw, &ccgw, sizeof(ccgw));
835 goto out;
836 879
837 err = -ENODEV; 880 err = -ENODEV;
838 881
839 /* ifindex == 0 is not allowed for job creation */
840 if (!gwj->ccgw.src_idx || !gwj->ccgw.dst_idx)
841 goto out;
842
843 gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx); 882 gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx);
844 883
845 if (!gwj->src.dev) 884 if (!gwj->src.dev)
@@ -856,8 +895,6 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
856 if (gwj->dst.dev->type != ARPHRD_CAN) 895 if (gwj->dst.dev->type != ARPHRD_CAN)
857 goto out; 896 goto out;
858 897
859 gwj->limit_hops = limhops;
860
861 ASSERT_RTNL(); 898 ASSERT_RTNL();
862 899
863 err = cgw_register_filter(gwj); 900 err = cgw_register_filter(gwj);
@@ -931,8 +968,15 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
931 if (gwj->limit_hops != limhops) 968 if (gwj->limit_hops != limhops)
932 continue; 969 continue;
933 970
934 if (memcmp(&gwj->mod, &mod, sizeof(mod))) 971 /* we have a match when uid is enabled and identical */
935 continue; 972 if (gwj->mod.uid || mod.uid) {
973 if (gwj->mod.uid != mod.uid)
974 continue;
975 } else {
976 /* no uid => check for identical modifications */
977 if (memcmp(&gwj->mod, &mod, sizeof(mod)))
978 continue;
979 }
936 980
937 /* if (r->gwtype == CGW_TYPE_CAN_CAN) - is made sure here */ 981 /* if (r->gwtype == CGW_TYPE_CAN_CAN) - is made sure here */
938 if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw))) 982 if (memcmp(&gwj->ccgw, &ccgw, sizeof(ccgw)))