@@ -146,6 +146,7 @@ struct cgw_job {
146146 /* tbc */
147147 };
148148 u8 gwtype ;
149+ u8 limit_hops ;
149150 u16 flags ;
150151};
151152
@@ -402,6 +403,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
402403
403404 /* put the incremented hop counter in the cloned skb */
404405 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+
405411 nskb -> dev = gwj -> dst .dev ;
406412
407413 /* pointer to modifiable CAN frame */
@@ -509,6 +515,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
509515
510516 /* check non default settings of attributes */
511517
518+ if (gwj -> limit_hops ) {
519+ if (nla_put_u8 (skb , CGW_LIM_HOPS , gwj -> limit_hops ) < 0 )
520+ goto cancel ;
521+ }
522+
512523 if (gwj -> mod .modtype .and ) {
513524 memcpy (& mb .cf , & gwj -> mod .modframe .and , sizeof (mb .cf ));
514525 mb .modtype = gwj -> mod .modtype .and ;
@@ -606,11 +617,12 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = {
606617 [CGW_SRC_IF ] = { .type = NLA_U32 },
607618 [CGW_DST_IF ] = { .type = NLA_U32 },
608619 [CGW_FILTER ] = { .len = sizeof (struct can_filter ) },
620+ [CGW_LIM_HOPS ] = { .type = NLA_U8 },
609621};
610622
611623/* check for common and gwtype specific attributes */
612624static int cgw_parse_attr (struct nlmsghdr * nlh , struct cf_mod * mod ,
613- u8 gwtype , void * gwtypeattr )
625+ u8 gwtype , void * gwtypeattr , u8 * limhops )
614626{
615627 struct nlattr * tb [CGW_MAX + 1 ];
616628 struct cgw_frame_mod mb ;
@@ -625,6 +637,13 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
625637 if (err < 0 )
626638 return err ;
627639
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+
628647 /* check for AND/OR/XOR/SET modifications */
629648
630649 if (tb [CGW_MOD_AND ]) {
@@ -782,6 +801,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
782801{
783802 struct rtcanmsg * r ;
784803 struct cgw_job * gwj ;
804+ u8 limhops = 0 ;
785805 int err = 0 ;
786806
787807 if (!capable (CAP_NET_ADMIN ))
@@ -808,7 +828,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
808828 gwj -> flags = r -> flags ;
809829 gwj -> gwtype = r -> gwtype ;
810830
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 );
812833 if (err < 0 )
813834 goto out ;
814835
@@ -836,6 +857,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
836857 if (gwj -> dst .dev -> type != ARPHRD_CAN || gwj -> dst .dev -> header_ops )
837858 goto put_src_dst_out ;
838859
860+ gwj -> limit_hops = limhops ;
861+
839862 ASSERT_RTNL ();
840863
841864 err = cgw_register_filter (gwj );
@@ -867,13 +890,14 @@ static void cgw_remove_all_jobs(void)
867890 }
868891}
869892
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 )
871894{
872895 struct cgw_job * gwj = NULL ;
873896 struct hlist_node * nx ;
874897 struct rtcanmsg * r ;
875898 struct cf_mod mod ;
876899 struct can_can_gw ccgw ;
900+ u8 limhops = 0 ;
877901 int err = 0 ;
878902
879903 if (!capable (CAP_NET_ADMIN ))
@@ -890,7 +914,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
890914 if (r -> gwtype != CGW_TYPE_CAN_CAN )
891915 return - EINVAL ;
892916
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 );
894918 if (err < 0 )
895919 return err ;
896920
@@ -910,6 +934,9 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
910934 if (gwj -> flags != r -> flags )
911935 continue ;
912936
937+ if (gwj -> limit_hops != limhops )
938+ continue ;
939+
913940 if (memcmp (& gwj -> mod , & mod , sizeof (mod )))
914941 continue ;
915942
0 commit comments