diff options
author | Oliver Hartkopp <socketcan@hartkopp.net> | 2013-08-26 09:05:36 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2013-08-29 16:58:24 -0400 |
commit | 391ac1282dd7ff1cb8245cccc5262e8e4173edc4 (patch) | |
tree | 891c2d57e8b2424b72e07815b7f203317257c93e /net | |
parent | 1149108e2fbf98899447d4567901bf07825ee576 (diff) |
can: gw: add a per rule limitation of frame hops
Usually the received CAN frames can be processed/routed as much as 'max_hops'
times (which is given at module load time of the can-gw module).
Introduce a new configuration option to reduce the number of possible hops
for a specific gateway rule to a value smaller then max_hops.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'net')
-rw-r--r-- | net/can/gw.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/net/can/gw.c b/net/can/gw.c index 2f291f961a17..3f9b0f3a2818 100644 --- a/net/can/gw.c +++ b/net/can/gw.c | |||
@@ -146,6 +146,7 @@ struct cgw_job { | |||
146 | /* tbc */ | 146 | /* tbc */ |
147 | }; | 147 | }; |
148 | u8 gwtype; | 148 | u8 gwtype; |
149 | u8 limit_hops; | ||
149 | u16 flags; | 150 | u16 flags; |
150 | }; | 151 | }; |
151 | 152 | ||
@@ -402,6 +403,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) | |||
402 | 403 | ||
403 | /* put the incremented hop counter in the cloned skb */ | 404 | /* put the incremented hop counter in the cloned skb */ |
404 | cgw_hops(nskb) = cgw_hops(skb) + 1; | 405 | cgw_hops(nskb) = cgw_hops(skb) + 1; |
406 | |||
407 | /* first processing of this CAN frame -> adjust to private hop limit */ | ||
408 | if (gwj->limit_hops && cgw_hops(nskb) == 1) | ||
409 | cgw_hops(nskb) = max_hops - gwj->limit_hops + 1; | ||
410 | |||
405 | nskb->dev = gwj->dst.dev; | 411 | nskb->dev = gwj->dst.dev; |
406 | 412 | ||
407 | /* pointer to modifiable CAN frame */ | 413 | /* pointer to modifiable CAN frame */ |
@@ -509,6 +515,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type, | |||
509 | 515 | ||
510 | /* check non default settings of attributes */ | 516 | /* check non default settings of attributes */ |
511 | 517 | ||
518 | if (gwj->limit_hops) { | ||
519 | if (nla_put_u8(skb, CGW_LIM_HOPS, gwj->limit_hops) < 0) | ||
520 | goto cancel; | ||
521 | } | ||
522 | |||
512 | if (gwj->mod.modtype.and) { | 523 | if (gwj->mod.modtype.and) { |
513 | memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); | 524 | memcpy(&mb.cf, &gwj->mod.modframe.and, sizeof(mb.cf)); |
514 | mb.modtype = gwj->mod.modtype.and; | 525 | mb.modtype = gwj->mod.modtype.and; |
@@ -606,11 +617,12 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = { | |||
606 | [CGW_SRC_IF] = { .type = NLA_U32 }, | 617 | [CGW_SRC_IF] = { .type = NLA_U32 }, |
607 | [CGW_DST_IF] = { .type = NLA_U32 }, | 618 | [CGW_DST_IF] = { .type = NLA_U32 }, |
608 | [CGW_FILTER] = { .len = sizeof(struct can_filter) }, | 619 | [CGW_FILTER] = { .len = sizeof(struct can_filter) }, |
620 | [CGW_LIM_HOPS] = { .type = NLA_U8 }, | ||
609 | }; | 621 | }; |
610 | 622 | ||
611 | /* check for common and gwtype specific attributes */ | 623 | /* check for common and gwtype specific attributes */ |
612 | static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, | 624 | static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, |
613 | u8 gwtype, void *gwtypeattr) | 625 | u8 gwtype, void *gwtypeattr, u8 *limhops) |
614 | { | 626 | { |
615 | struct nlattr *tb[CGW_MAX+1]; | 627 | struct nlattr *tb[CGW_MAX+1]; |
616 | struct cgw_frame_mod mb; | 628 | struct cgw_frame_mod mb; |
@@ -625,6 +637,13 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod, | |||
625 | if (err < 0) | 637 | if (err < 0) |
626 | return err; | 638 | return err; |
627 | 639 | ||
640 | if (tb[CGW_LIM_HOPS]) { | ||
641 | *limhops = nla_get_u8(tb[CGW_LIM_HOPS]); | ||
642 | |||
643 | if (*limhops < 1 || *limhops > max_hops) | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
628 | /* check for AND/OR/XOR/SET modifications */ | 647 | /* check for AND/OR/XOR/SET modifications */ |
629 | 648 | ||
630 | if (tb[CGW_MOD_AND]) { | 649 | if (tb[CGW_MOD_AND]) { |
@@ -782,6 +801,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
782 | { | 801 | { |
783 | struct rtcanmsg *r; | 802 | struct rtcanmsg *r; |
784 | struct cgw_job *gwj; | 803 | struct cgw_job *gwj; |
804 | u8 limhops = 0; | ||
785 | int err = 0; | 805 | int err = 0; |
786 | 806 | ||
787 | if (!capable(CAP_NET_ADMIN)) | 807 | if (!capable(CAP_NET_ADMIN)) |
@@ -808,7 +828,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
808 | gwj->flags = r->flags; | 828 | gwj->flags = r->flags; |
809 | gwj->gwtype = r->gwtype; | 829 | gwj->gwtype = r->gwtype; |
810 | 830 | ||
811 | err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw); | 831 | err = cgw_parse_attr(nlh, &gwj->mod, CGW_TYPE_CAN_CAN, &gwj->ccgw, |
832 | &limhops); | ||
812 | if (err < 0) | 833 | if (err < 0) |
813 | goto out; | 834 | goto out; |
814 | 835 | ||
@@ -836,6 +857,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
836 | if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops) | 857 | if (gwj->dst.dev->type != ARPHRD_CAN || gwj->dst.dev->header_ops) |
837 | goto put_src_dst_out; | 858 | goto put_src_dst_out; |
838 | 859 | ||
860 | gwj->limit_hops = limhops; | ||
861 | |||
839 | ASSERT_RTNL(); | 862 | ASSERT_RTNL(); |
840 | 863 | ||
841 | err = cgw_register_filter(gwj); | 864 | err = cgw_register_filter(gwj); |
@@ -867,13 +890,14 @@ static void cgw_remove_all_jobs(void) | |||
867 | } | 890 | } |
868 | } | 891 | } |
869 | 892 | ||
870 | static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) | 893 | static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) |
871 | { | 894 | { |
872 | struct cgw_job *gwj = NULL; | 895 | struct cgw_job *gwj = NULL; |
873 | struct hlist_node *nx; | 896 | struct hlist_node *nx; |
874 | struct rtcanmsg *r; | 897 | struct rtcanmsg *r; |
875 | struct cf_mod mod; | 898 | struct cf_mod mod; |
876 | struct can_can_gw ccgw; | 899 | struct can_can_gw ccgw; |
900 | u8 limhops = 0; | ||
877 | int err = 0; | 901 | int err = 0; |
878 | 902 | ||
879 | if (!capable(CAP_NET_ADMIN)) | 903 | if (!capable(CAP_NET_ADMIN)) |
@@ -890,7 +914,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
890 | if (r->gwtype != CGW_TYPE_CAN_CAN) | 914 | if (r->gwtype != CGW_TYPE_CAN_CAN) |
891 | return -EINVAL; | 915 | return -EINVAL; |
892 | 916 | ||
893 | err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw); | 917 | err = cgw_parse_attr(nlh, &mod, CGW_TYPE_CAN_CAN, &ccgw, &limhops); |
894 | if (err < 0) | 918 | if (err < 0) |
895 | return err; | 919 | return err; |
896 | 920 | ||
@@ -910,6 +934,9 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
910 | if (gwj->flags != r->flags) | 934 | if (gwj->flags != r->flags) |
911 | continue; | 935 | continue; |
912 | 936 | ||
937 | if (gwj->limit_hops != limhops) | ||
938 | continue; | ||
939 | |||
913 | if (memcmp(&gwj->mod, &mod, sizeof(mod))) | 940 | if (memcmp(&gwj->mod, &mod, sizeof(mod))) |
914 | continue; | 941 | continue; |
915 | 942 | ||