diff options
| author | Oliver Hartkopp <socketcan@hartkopp.net> | 2012-06-13 14:48:21 -0400 |
|---|---|---|
| committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2012-06-19 15:40:14 -0400 |
| commit | 1e0625facab2e871472472b7df87d8fbe6caf75a (patch) | |
| tree | 831d0adba939e1d19e33d59b73508b5d306ed412 | |
| parent | e2d265d3b587f5f6f8febc0222aace93302ff0be (diff) | |
candev: add/update helpers for CAN FD
- update sanity checks
- add DLC to length conversion helpers
- can_dlc2len() - get data length from can_dlc with sanitized can_dlc
- can_len2dlc() - map the sanitized data length to an appropriate DLC
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
| -rw-r--r-- | drivers/net/can/dev.c | 35 | ||||
| -rw-r--r-- | include/linux/can/dev.h | 33 |
2 files changed, 59 insertions, 9 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index f03d7a481a80..239e4dd92ca1 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c | |||
| @@ -33,6 +33,39 @@ MODULE_DESCRIPTION(MOD_DESC); | |||
| 33 | MODULE_LICENSE("GPL v2"); | 33 | MODULE_LICENSE("GPL v2"); |
| 34 | MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); | 34 | MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); |
| 35 | 35 | ||
| 36 | /* CAN DLC to real data length conversion helpers */ | ||
| 37 | |||
| 38 | static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7, | ||
| 39 | 8, 12, 16, 20, 24, 32, 48, 64}; | ||
| 40 | |||
| 41 | /* get data length from can_dlc with sanitized can_dlc */ | ||
| 42 | u8 can_dlc2len(u8 can_dlc) | ||
| 43 | { | ||
| 44 | return dlc2len[can_dlc & 0x0F]; | ||
| 45 | } | ||
| 46 | EXPORT_SYMBOL_GPL(can_dlc2len); | ||
| 47 | |||
| 48 | static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ | ||
| 49 | 9, 9, 9, 9, /* 9 - 12 */ | ||
| 50 | 10, 10, 10, 10, /* 13 - 16 */ | ||
| 51 | 11, 11, 11, 11, /* 17 - 20 */ | ||
| 52 | 12, 12, 12, 12, /* 21 - 24 */ | ||
| 53 | 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */ | ||
| 54 | 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */ | ||
| 55 | 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */ | ||
| 56 | 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */ | ||
| 57 | 15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */ | ||
| 58 | |||
| 59 | /* map the sanitized data length to an appropriate data length code */ | ||
| 60 | u8 can_len2dlc(u8 len) | ||
| 61 | { | ||
| 62 | if (unlikely(len > 64)) | ||
| 63 | return 0xF; | ||
| 64 | |||
| 65 | return len2dlc[len]; | ||
| 66 | } | ||
| 67 | EXPORT_SYMBOL_GPL(can_len2dlc); | ||
| 68 | |||
| 36 | #ifdef CONFIG_CAN_CALC_BITTIMING | 69 | #ifdef CONFIG_CAN_CALC_BITTIMING |
| 37 | #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ | 70 | #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ |
| 38 | 71 | ||
| @@ -454,7 +487,7 @@ EXPORT_SYMBOL_GPL(can_bus_off); | |||
| 454 | static void can_setup(struct net_device *dev) | 487 | static void can_setup(struct net_device *dev) |
| 455 | { | 488 | { |
| 456 | dev->type = ARPHRD_CAN; | 489 | dev->type = ARPHRD_CAN; |
| 457 | dev->mtu = sizeof(struct can_frame); | 490 | dev->mtu = CAN_MTU; |
| 458 | dev->hard_header_len = 0; | 491 | dev->hard_header_len = 0; |
| 459 | dev->addr_len = 0; | 492 | dev->addr_len = 0; |
| 460 | dev->tx_queue_len = 10; | 493 | dev->tx_queue_len = 10; |
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 5d2efe7e3f1b..ee5a771fb20d 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h | |||
| @@ -61,23 +61,40 @@ struct can_priv { | |||
| 61 | * To be used in the CAN netdriver receive path to ensure conformance with | 61 | * To be used in the CAN netdriver receive path to ensure conformance with |
| 62 | * ISO 11898-1 Chapter 8.4.2.3 (DLC field) | 62 | * ISO 11898-1 Chapter 8.4.2.3 (DLC field) |
| 63 | */ | 63 | */ |
| 64 | #define get_can_dlc(i) (min_t(__u8, (i), 8)) | 64 | #define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC)) |
| 65 | #define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC)) | ||
| 65 | 66 | ||
| 66 | /* Drop a given socketbuffer if it does not contain a valid CAN frame. */ | 67 | /* Drop a given socketbuffer if it does not contain a valid CAN frame. */ |
| 67 | static inline int can_dropped_invalid_skb(struct net_device *dev, | 68 | static inline int can_dropped_invalid_skb(struct net_device *dev, |
| 68 | struct sk_buff *skb) | 69 | struct sk_buff *skb) |
| 69 | { | 70 | { |
| 70 | const struct can_frame *cf = (struct can_frame *)skb->data; | 71 | const struct canfd_frame *cfd = (struct canfd_frame *)skb->data; |
| 71 | 72 | ||
| 72 | if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) { | 73 | if (skb->protocol == htons(ETH_P_CAN)) { |
| 73 | kfree_skb(skb); | 74 | if (unlikely(skb->len != CAN_MTU || |
| 74 | dev->stats.tx_dropped++; | 75 | cfd->len > CAN_MAX_DLEN)) |
| 75 | return 1; | 76 | goto inval_skb; |
| 76 | } | 77 | } else if (skb->protocol == htons(ETH_P_CANFD)) { |
| 78 | if (unlikely(skb->len != CANFD_MTU || | ||
| 79 | cfd->len > CANFD_MAX_DLEN)) | ||
| 80 | goto inval_skb; | ||
| 81 | } else | ||
| 82 | goto inval_skb; | ||
| 77 | 83 | ||
| 78 | return 0; | 84 | return 0; |
| 85 | |||
| 86 | inval_skb: | ||
| 87 | kfree_skb(skb); | ||
| 88 | dev->stats.tx_dropped++; | ||
| 89 | return 1; | ||
| 79 | } | 90 | } |
| 80 | 91 | ||
| 92 | /* get data length from can_dlc with sanitized can_dlc */ | ||
| 93 | u8 can_dlc2len(u8 can_dlc); | ||
| 94 | |||
| 95 | /* map the sanitized data length to an appropriate data length code */ | ||
| 96 | u8 can_len2dlc(u8 len); | ||
| 97 | |||
| 81 | struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max); | 98 | struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max); |
| 82 | void free_candev(struct net_device *dev); | 99 | void free_candev(struct net_device *dev); |
| 83 | 100 | ||
