candev: add/update helpers for CAN FD
authorOliver Hartkopp <socketcan@hartkopp.net>
Wed, 13 Jun 2012 18:48:21 +0000 (20:48 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 19 Jun 2012 19:40:14 +0000 (21:40 +0200)
- 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>
drivers/net/can/dev.c
include/linux/can/dev.h

index f03d7a481a809902ea03ada0bb4ff6c9f2ca5196..239e4dd92ca1af77cc29df6bcd1563d6e6b7cd06 100644 (file)
@@ -33,6 +33,39 @@ MODULE_DESCRIPTION(MOD_DESC);
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 
+/* CAN DLC to real data length conversion helpers */
+
+static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
+                            8, 12, 16, 20, 24, 32, 48, 64};
+
+/* get data length from can_dlc with sanitized can_dlc */
+u8 can_dlc2len(u8 can_dlc)
+{
+       return dlc2len[can_dlc & 0x0F];
+}
+EXPORT_SYMBOL_GPL(can_dlc2len);
+
+static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8,                /* 0 - 8 */
+                            9, 9, 9, 9,                        /* 9 - 12 */
+                            10, 10, 10, 10,                    /* 13 - 16 */
+                            11, 11, 11, 11,                    /* 17 - 20 */
+                            12, 12, 12, 12,                    /* 21 - 24 */
+                            13, 13, 13, 13, 13, 13, 13, 13,    /* 25 - 32 */
+                            14, 14, 14, 14, 14, 14, 14, 14,    /* 33 - 40 */
+                            14, 14, 14, 14, 14, 14, 14, 14,    /* 41 - 48 */
+                            15, 15, 15, 15, 15, 15, 15, 15,    /* 49 - 56 */
+                            15, 15, 15, 15, 15, 15, 15, 15};   /* 57 - 64 */
+
+/* map the sanitized data length to an appropriate data length code */
+u8 can_len2dlc(u8 len)
+{
+       if (unlikely(len > 64))
+               return 0xF;
+
+       return len2dlc[len];
+}
+EXPORT_SYMBOL_GPL(can_len2dlc);
+
 #ifdef CONFIG_CAN_CALC_BITTIMING
 #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
 
@@ -454,7 +487,7 @@ EXPORT_SYMBOL_GPL(can_bus_off);
 static void can_setup(struct net_device *dev)
 {
        dev->type = ARPHRD_CAN;
-       dev->mtu = sizeof(struct can_frame);
+       dev->mtu = CAN_MTU;
        dev->hard_header_len = 0;
        dev->addr_len = 0;
        dev->tx_queue_len = 10;
index 5d2efe7e3f1bfb97429cbb30e8d0b31395ced8ac..ee5a771fb20d207cff444ec6f6310416713a5443 100644 (file)
@@ -61,23 +61,40 @@ struct can_priv {
  * To be used in the CAN netdriver receive path to ensure conformance with
  * ISO 11898-1 Chapter 8.4.2.3 (DLC field)
  */
-#define get_can_dlc(i) (min_t(__u8, (i), 8))
+#define get_can_dlc(i)         (min_t(__u8, (i), CAN_MAX_DLC))
+#define get_canfd_dlc(i)       (min_t(__u8, (i), CANFD_MAX_DLC))
 
 /* Drop a given socketbuffer if it does not contain a valid CAN frame. */
 static inline int can_dropped_invalid_skb(struct net_device *dev,
                                          struct sk_buff *skb)
 {
-       const struct can_frame *cf = (struct can_frame *)skb->data;
-
-       if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) {
-               kfree_skb(skb);
-               dev->stats.tx_dropped++;
-               return 1;
-       }
+       const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+       if (skb->protocol == htons(ETH_P_CAN)) {
+               if (unlikely(skb->len != CAN_MTU ||
+                            cfd->len > CAN_MAX_DLEN))
+                       goto inval_skb;
+       } else if (skb->protocol == htons(ETH_P_CANFD)) {
+               if (unlikely(skb->len != CANFD_MTU ||
+                            cfd->len > CANFD_MAX_DLEN))
+                       goto inval_skb;
+       } else
+               goto inval_skb;
 
        return 0;
+
+inval_skb:
+       kfree_skb(skb);
+       dev->stats.tx_dropped++;
+       return 1;
 }
 
+/* get data length from can_dlc with sanitized can_dlc */
+u8 can_dlc2len(u8 can_dlc);
+
+/* map the sanitized data length to an appropriate data length code */
+u8 can_len2dlc(u8 len);
+
 struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
 void free_candev(struct net_device *dev);