@ -146,6 +146,7 @@ struct cgw_job {
/* tbc */
} ;
u8 gwtype ;
u8 limit_hops ;
u16 flags ;
} ;
@ -402,6 +403,11 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
/* put the incremented hop counter in the cloned skb */
cgw_hops ( nskb ) = cgw_hops ( skb ) + 1 ;
/* first processing of this CAN frame -> adjust to private hop limit */
if ( gwj - > limit_hops & & cgw_hops ( nskb ) = = 1 )
cgw_hops ( nskb ) = max_hops - gwj - > limit_hops + 1 ;
nskb - > dev = gwj - > dst . dev ;
/* pointer to modifiable CAN frame */
@ -509,6 +515,11 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
/* check non default settings of attributes */
if ( gwj - > limit_hops ) {
if ( nla_put_u8 ( skb , CGW_LIM_HOPS , gwj - > limit_hops ) < 0 )
goto cancel ;
}
if ( gwj - > mod . modtype . and ) {
memcpy ( & mb . cf , & gwj - > mod . modframe . and , sizeof ( mb . cf ) ) ;
mb . modtype = gwj - > mod . modtype . and ;
@ -606,11 +617,12 @@ static const struct nla_policy cgw_policy[CGW_MAX+1] = {
[ CGW_SRC_IF ] = { . type = NLA_U32 } ,
[ CGW_DST_IF ] = { . type = NLA_U32 } ,
[ CGW_FILTER ] = { . len = sizeof ( struct can_filter ) } ,
[ CGW_LIM_HOPS ] = { . type = NLA_U8 } ,
} ;
/* check for common and gwtype specific attributes */
static int cgw_parse_attr ( struct nlmsghdr * nlh , struct cf_mod * mod ,
u8 gwtype , void * gwtypeattr )
u8 gwtype , void * gwtypeattr , u8 * limhops )
{
struct nlattr * tb [ CGW_MAX + 1 ] ;
struct cgw_frame_mod mb ;
@ -625,6 +637,13 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
if ( err < 0 )
return err ;
if ( tb [ CGW_LIM_HOPS ] ) {
* limhops = nla_get_u8 ( tb [ CGW_LIM_HOPS ] ) ;
if ( * limhops < 1 | | * limhops > max_hops )
return - EINVAL ;
}
/* check for AND/OR/XOR/SET modifications */
if ( tb [ CGW_MOD_AND ] ) {
@ -782,6 +801,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct rtcanmsg * r ;
struct cgw_job * gwj ;
u8 limhops = 0 ;
int err = 0 ;
if ( ! capable ( CAP_NET_ADMIN ) )
@ -808,7 +828,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
gwj - > flags = r - > flags ;
gwj - > gwtype = r - > gwtype ;
err = cgw_parse_attr ( nlh , & gwj - > mod , CGW_TYPE_CAN_CAN , & gwj - > ccgw ) ;
err = cgw_parse_attr ( nlh , & gwj - > mod , CGW_TYPE_CAN_CAN , & gwj - > ccgw ,
& limhops ) ;
if ( err < 0 )
goto out ;
@ -836,6 +857,8 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
if ( gwj - > dst . dev - > type ! = ARPHRD_CAN | | gwj - > dst . dev - > header_ops )
goto put_src_dst_out ;
gwj - > limit_hops = limhops ;
ASSERT_RTNL ( ) ;
err = cgw_register_filter ( gwj ) ;
@ -867,13 +890,14 @@ static void cgw_remove_all_jobs(void)
}
}
static int cgw_remove_job ( struct sk_buff * skb , struct nlmsghdr * nlh )
static int cgw_remove_job ( struct sk_buff * skb , struct nlmsghdr * nlh )
{
struct cgw_job * gwj = NULL ;
struct hlist_node * nx ;
struct rtcanmsg * r ;
struct cf_mod mod ;
struct can_can_gw ccgw ;
u8 limhops = 0 ;
int err = 0 ;
if ( ! capable ( CAP_NET_ADMIN ) )
@ -890,7 +914,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
if ( r - > gwtype ! = CGW_TYPE_CAN_CAN )
return - EINVAL ;
err = cgw_parse_attr ( nlh , & mod , CGW_TYPE_CAN_CAN , & ccgw ) ;
err = cgw_parse_attr ( nlh , & mod , CGW_TYPE_CAN_CAN , & ccgw , & limhops ) ;
if ( err < 0 )
return err ;
@ -910,6 +934,9 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
if ( gwj - > flags ! = r - > flags )
continue ;
if ( gwj - > limit_hops ! = limhops )
continue ;
if ( memcmp ( & gwj - > mod , & mod , sizeof ( mod ) ) )
continue ;