can: canxl: update CAN infrastructure for CAN XL frames
[platform/kernel/linux-starfive.git] / include / linux / can / skb.h
index 182749e..1abc25a 100644 (file)
@@ -20,7 +20,8 @@ void can_flush_echo_skb(struct net_device *dev);
 int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
                     unsigned int idx, unsigned int frame_len);
 struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx,
-                                  u8 *len_ptr, unsigned int *frame_len_ptr);
+                                  unsigned int *len_ptr,
+                                  unsigned int *frame_len_ptr);
 unsigned int __must_check can_get_echo_skb(struct net_device *dev,
                                           unsigned int idx,
                                           unsigned int *frame_len_ptr);
@@ -29,6 +30,9 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
 struct sk_buff *alloc_canfd_skb(struct net_device *dev,
                                struct canfd_frame **cfd);
+struct sk_buff *alloc_canxl_skb(struct net_device *dev,
+                               struct canxl_frame **cxl,
+                               unsigned int data_len);
 struct sk_buff *alloc_can_err_skb(struct net_device *dev,
                                  struct can_frame **cf);
 bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb);
@@ -97,10 +101,59 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
        return nskb;
 }
 
+static inline bool can_is_can_skb(const struct sk_buff *skb)
+{
+       struct can_frame *cf = (struct can_frame *)skb->data;
+
+       /* the CAN specific type of skb is identified by its data length */
+       return (skb->len == CAN_MTU && cf->len <= CAN_MAX_DLEN);
+}
+
 static inline bool can_is_canfd_skb(const struct sk_buff *skb)
 {
+       struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
        /* the CAN specific type of skb is identified by its data length */
-       return skb->len == CANFD_MTU;
+       return (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN);
+}
+
+static inline bool can_is_canxl_skb(const struct sk_buff *skb)
+{
+       const struct canxl_frame *cxl = (struct canxl_frame *)skb->data;
+
+       if (skb->len < CANXL_HDR_SIZE + CANXL_MIN_DLEN || skb->len > CANXL_MTU)
+               return false;
+
+       /* this also checks valid CAN XL data length boundaries */
+       if (skb->len != CANXL_HDR_SIZE + cxl->len)
+               return false;
+
+       return cxl->flags & CANXL_XLF;
+}
+
+/* get length element value from can[|fd|xl]_frame structure */
+static inline unsigned int can_skb_get_len_val(struct sk_buff *skb)
+{
+       const struct canxl_frame *cxl = (struct canxl_frame *)skb->data;
+       const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+
+       if (can_is_canxl_skb(skb))
+               return cxl->len;
+
+       return cfd->len;
+}
+
+/* get needed data length inside CAN frame for all frame types (RTR aware) */
+static inline unsigned int can_skb_get_data_len(struct sk_buff *skb)
+{
+       unsigned int len = can_skb_get_len_val(skb);
+       const struct can_frame *cf = (struct can_frame *)skb->data;
+
+       /* RTR frames have an actual length of zero */
+       if (can_is_can_skb(skb) && cf->can_id & CAN_RTR_FLAG)
+               return 0;
+
+       return len;
 }
 
 #endif /* !_CAN_SKB_H */