diff options
Diffstat (limited to 'net/can/gw.c')
| -rw-r--r-- | net/can/gw.c | 68 |
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))) |
