can: canxl: update CAN infrastructure for CAN XL frames
[platform/kernel/linux-starfive.git] / drivers / net / can / dev / skb.c
index adb413b..791a51e 100644 (file)
@@ -187,6 +187,20 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
 }
 EXPORT_SYMBOL_GPL(can_free_echo_skb);
 
+/* fill common values for CAN sk_buffs */
+static void init_can_skb_reserve(struct sk_buff *skb)
+{
+       skb->pkt_type = PACKET_BROADCAST;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
+
+       can_skb_reserve(skb);
+       can_skb_prv(skb)->skbcnt = 0;
+}
+
 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
 {
        struct sk_buff *skb;
@@ -200,16 +214,8 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
        }
 
        skb->protocol = htons(ETH_P_CAN);
-       skb->pkt_type = PACKET_BROADCAST;
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-       skb_reset_mac_header(skb);
-       skb_reset_network_header(skb);
-       skb_reset_transport_header(skb);
-
-       can_skb_reserve(skb);
+       init_can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
-       can_skb_prv(skb)->skbcnt = 0;
 
        *cf = skb_put_zero(skb, sizeof(struct can_frame));
 
@@ -231,16 +237,8 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
        }
 
        skb->protocol = htons(ETH_P_CANFD);
-       skb->pkt_type = PACKET_BROADCAST;
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-       skb_reset_mac_header(skb);
-       skb_reset_network_header(skb);
-       skb_reset_transport_header(skb);
-
-       can_skb_reserve(skb);
+       init_can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
-       can_skb_prv(skb)->skbcnt = 0;
 
        *cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
 
@@ -251,6 +249,39 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
 }
 EXPORT_SYMBOL_GPL(alloc_canfd_skb);
 
+struct sk_buff *alloc_canxl_skb(struct net_device *dev,
+                               struct canxl_frame **cxl,
+                               unsigned int data_len)
+{
+       struct sk_buff *skb;
+
+       if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN)
+               goto out_error;
+
+       skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+                              CANXL_HDR_SIZE + data_len);
+       if (unlikely(!skb))
+               goto out_error;
+
+       skb->protocol = htons(ETH_P_CANXL);
+       init_can_skb_reserve(skb);
+       can_skb_prv(skb)->ifindex = dev->ifindex;
+
+       *cxl = skb_put_zero(skb, CANXL_HDR_SIZE + data_len);
+
+       /* set CAN XL flag and length information by default */
+       (*cxl)->flags = CANXL_XLF;
+       (*cxl)->len = data_len;
+
+       return skb;
+
+out_error:
+       *cxl = NULL;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(alloc_canxl_skb);
+
 struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
 {
        struct sk_buff *skb;
@@ -319,6 +350,11 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
                        goto inval_skb;
                break;
 
+       case ETH_P_CANXL:
+               if (!can_is_canxl_skb(skb))
+                       goto inval_skb;
+               break;
+
        default:
                goto inval_skb;
        }