Skip to content

Commit 391ac12

Browse files
hartkoppmarckleinebudde
authored andcommitted
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 <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 1149108 commit 391ac12

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

include/uapi/linux/can/gw.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ enum {
4545
CGW_DST_IF, /* ifindex of destination network interface */
4646
CGW_FILTER, /* specify struct can_filter on source CAN device */
4747
CGW_DELETED, /* number of deleted CAN frames (see max_hops param) */
48+
CGW_LIM_HOPS, /* limit the number of hops of this specific rule */
4849
__CGW_MAX
4950
};
5051

@@ -116,13 +117,19 @@ enum {
116117
* Sets a CAN receive filter for the gateway job specified by the
117118
* struct can_filter described in include/linux/can.h
118119
*
119-
* CGW_MOD_XXX (length 17 bytes):
120+
* CGW_MOD_(AND|OR|XOR|SET) (length 17 bytes):
120121
* Specifies a modification that's done to a received CAN frame before it is
121122
* send out to the destination interface.
122123
*
123124
* <struct can_frame> data used as operator
124125
* <u8> affected CAN frame elements
125126
*
127+
* CGW_LIM_HOPS (length 1 byte):
128+
* Limit the number of hops of this specific rule. Usually the received CAN
129+
* frame can be processed as much as 'max_hops' times (which is given at module
130+
* load time of the can-gw module). This value is used to reduce the number of
131+
* possible hops for this gateway rule to a value smaller then max_hops.
132+
*
126133
* CGW_CS_XOR (length 4 bytes):
127134
* Set a simple XOR checksum starting with an initial value into
128135
* data[result-idx] using data[start-idx] .. data[end-idx]

net/can/gw.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
612624
static 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

Comments
 (0)