summaryrefslogtreecommitdiffstats
path: root/net/can/gw.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/can/gw.c')
-rw-r--r--net/can/gw.c68
1 files changed, 56 insertions, 12 deletions
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)))