Commit be286bafe1f4069094865264f29805854c5788bf
Committed by
Marc Kleine-Budde
1 parent
d904d3edcb
Exists in
master
and in
20 other branches
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>
Showing 1 changed file with 40 additions and 16 deletions Side-by-side Diff
net/can/gw.c
... | ... | @@ -42,6 +42,7 @@ |
42 | 42 | #include <linux/module.h> |
43 | 43 | #include <linux/init.h> |
44 | 44 | #include <linux/types.h> |
45 | +#include <linux/kernel.h> | |
45 | 46 | #include <linux/list.h> |
46 | 47 | #include <linux/spinlock.h> |
47 | 48 | #include <linux/rcupdate.h> |
48 | 49 | |
49 | 50 | |
... | ... | @@ -58,15 +59,26 @@ |
58 | 59 | #include <net/net_namespace.h> |
59 | 60 | #include <net/sock.h> |
60 | 61 | |
61 | -#define CAN_GW_VERSION "20101209" | |
62 | -static __initconst const char banner[] = | |
63 | - KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n"; | |
62 | +#define CAN_GW_VERSION "20130117" | |
63 | +#define CAN_GW_NAME "can-gw" | |
64 | 64 | |
65 | 65 | MODULE_DESCRIPTION("PF_CAN netlink gateway"); |
66 | 66 | MODULE_LICENSE("Dual BSD/GPL"); |
67 | 67 | MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>"); |
68 | -MODULE_ALIAS("can-gw"); | |
68 | +MODULE_ALIAS(CAN_GW_NAME); | |
69 | 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) ")"); | |
81 | + | |
70 | 82 | static HLIST_HEAD(cgw_list); |
71 | 83 | static struct notifier_block notifier; |
72 | 84 | |
... | ... | @@ -339,8 +351,23 @@ |
339 | 351 | struct sk_buff *nskb; |
340 | 352 | int modidx = 0; |
341 | 353 | |
342 | - /* do not handle already routed frames - see comment below */ | |
343 | - if (skb_mac_header_was_set(skb)) | |
354 | + /* | |
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 | 371 | return; |
345 | 372 | |
346 | 373 | if (!(gwj->dst.dev->flags & IFF_UP)) { |
... | ... | @@ -371,15 +398,8 @@ |
371 | 398 | return; |
372 | 399 | } |
373 | 400 | |
374 | - /* | |
375 | - * Mark routed frames by setting some mac header length which is | |
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); | |
401 | + /* put the incremented hop counter in the cloned skb */ | |
402 | + cgw_hops(nskb) = cgw_hops(skb) + 1; | |
383 | 403 | nskb->dev = gwj->dst.dev; |
384 | 404 | |
385 | 405 | /* pointer to modifiable CAN frame */ |
... | ... | @@ -903,7 +923,11 @@ |
903 | 923 | |
904 | 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 | 932 | cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job), |
909 | 933 | 0, 0, NULL); |