diff options
author | Oliver Hartkopp <socketcan@hartkopp.net> | 2013-01-17 12:43:44 -0500 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2013-01-26 10:59:01 -0500 |
commit | be286bafe1f4069094865264f29805854c5788bf (patch) | |
tree | 1db2a2fa446d714e6b64630f6b6d91525d9f4984 /net/can | |
parent | d904d3edcbb26efc86ea3575bb4265559801a94b (diff) |
can: gw: add a variable limit for CAN frame routings
To prevent a possible misconfiguration (e.g. circular CAN frame routings)
limit the number of routings of a single CAN frame to a small variable value.
The limit can be specified by the module parameter 'max_hops' (1..6).
The default value is 1 (one hop), according to the original can-gw behaviour.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'net/can')
-rw-r--r-- | net/can/gw.c | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/net/can/gw.c b/net/can/gw.c index 37a3efb7cc9d..4216a80618cb 100644 --- a/net/can/gw.c +++ b/net/can/gw.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/module.h> | 42 | #include <linux/module.h> |
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/types.h> | 44 | #include <linux/types.h> |
45 | #include <linux/kernel.h> | ||
45 | #include <linux/list.h> | 46 | #include <linux/list.h> |
46 | #include <linux/spinlock.h> | 47 | #include <linux/spinlock.h> |
47 | #include <linux/rcupdate.h> | 48 | #include <linux/rcupdate.h> |
@@ -58,14 +59,25 @@ | |||
58 | #include <net/net_namespace.h> | 59 | #include <net/net_namespace.h> |
59 | #include <net/sock.h> | 60 | #include <net/sock.h> |
60 | 61 | ||
61 | #define CAN_GW_VERSION "20101209" | 62 | #define CAN_GW_VERSION "20130117" |
62 | static __initconst const char banner[] = | 63 | #define CAN_GW_NAME "can-gw" |
63 | KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n"; | ||
64 | 64 | ||
65 | MODULE_DESCRIPTION("PF_CAN netlink gateway"); | 65 | MODULE_DESCRIPTION("PF_CAN netlink gateway"); |
66 | MODULE_LICENSE("Dual BSD/GPL"); | 66 | MODULE_LICENSE("Dual BSD/GPL"); |
67 | MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>"); | 67 | MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>"); |
68 | MODULE_ALIAS("can-gw"); | 68 | MODULE_ALIAS(CAN_GW_NAME); |
69 | |||
70 | #define CGW_MIN_HOPS 1 | ||
71 | #define CGW_MAX_HOPS 6 | ||
72 | #define CGW_DEFAULT_HOPS 1 | ||
73 | |||
74 | static unsigned int max_hops __read_mostly = CGW_DEFAULT_HOPS; | ||
75 | module_param(max_hops, uint, S_IRUGO); | ||
76 | MODULE_PARM_DESC(max_hops, | ||
77 | "maximum " CAN_GW_NAME " routing hops for CAN frames " | ||
78 | "(valid values: " __stringify(CGW_MIN_HOPS) "-" | ||
79 | __stringify(CGW_MAX_HOPS) " hops, " | ||
80 | "default: " __stringify(CGW_DEFAULT_HOPS) ")"); | ||
69 | 81 | ||
70 | static HLIST_HEAD(cgw_list); | 82 | static HLIST_HEAD(cgw_list); |
71 | static struct notifier_block notifier; | 83 | static struct notifier_block notifier; |
@@ -339,8 +351,23 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) | |||
339 | struct sk_buff *nskb; | 351 | struct sk_buff *nskb; |
340 | int modidx = 0; | 352 | int modidx = 0; |
341 | 353 | ||
342 | /* do not handle already routed frames - see comment below */ | 354 | /* |
343 | if (skb_mac_header_was_set(skb)) | 355 | * Do not handle CAN frames routed more than 'max_hops' times. |
356 | * In general we should never catch this delimiter which is intended | ||
357 | * to cover a misconfiguration protection (e.g. circular CAN routes). | ||
358 | * | ||
359 | * The Controller Area Network controllers only accept CAN frames with | ||
360 | * correct CRCs - which are not visible in the controller registers. | ||
361 | * According to skbuff.h documentation the csum_start element for IP | ||
362 | * checksums is undefined/unsued when ip_summed == CHECKSUM_UNNECESSARY. | ||
363 | * Only CAN skbs can be processed here which already have this property. | ||
364 | */ | ||
365 | |||
366 | #define cgw_hops(skb) ((skb)->csum_start) | ||
367 | |||
368 | BUG_ON(skb->ip_summed != CHECKSUM_UNNECESSARY); | ||
369 | |||
370 | if (cgw_hops(skb) >= max_hops) | ||
344 | return; | 371 | return; |
345 | 372 | ||
346 | if (!(gwj->dst.dev->flags & IFF_UP)) { | 373 | if (!(gwj->dst.dev->flags & IFF_UP)) { |
@@ -371,15 +398,8 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) | |||
371 | return; | 398 | return; |
372 | } | 399 | } |
373 | 400 | ||
374 | /* | 401 | /* put the incremented hop counter in the cloned skb */ |
375 | * Mark routed frames by setting some mac header length which is | 402 | cgw_hops(nskb) = cgw_hops(skb) + 1; |
376 | * not relevant for the CAN frames located in the skb->data section. | ||
377 | * | ||
378 | * As dev->header_ops is not set in CAN netdevices no one is ever | ||
379 | * accessing the various header offsets in the CAN skbuffs anyway. | ||
380 | * E.g. using the packet socket to read CAN frames is still working. | ||
381 | */ | ||
382 | skb_set_mac_header(nskb, 8); | ||
383 | nskb->dev = gwj->dst.dev; | 403 | nskb->dev = gwj->dst.dev; |
384 | 404 | ||
385 | /* pointer to modifiable CAN frame */ | 405 | /* pointer to modifiable CAN frame */ |
@@ -903,7 +923,11 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
903 | 923 | ||
904 | static __init int cgw_module_init(void) | 924 | static __init int cgw_module_init(void) |
905 | { | 925 | { |
906 | printk(banner); | 926 | /* sanitize given module parameter */ |
927 | max_hops = clamp_t(unsigned int, max_hops, CGW_MIN_HOPS, CGW_MAX_HOPS); | ||
928 | |||
929 | pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n", | ||
930 | max_hops); | ||
907 | 931 | ||
908 | cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job), | 932 | cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job), |
909 | 0, 0, NULL); | 933 | 0, 0, NULL); |