Re: [PATCH v8 5/7] can: canxl: update CAN infrastructure for CAN XL frames

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue. 2 Aug. 2022 at 04:02, Oliver Hartkopp <socketcan@xxxxxxxxxxxx> wrote:
> - add new ETH_P_CANXL ethernet protocol type
> - update skb checks for CAN XL
> - add alloc_canxl_skb() which now needs a data length parameter
> - introduce init_can_skb_reserve() to reduce code duplication
>
> Signed-off-by: Oliver Hartkopp <socketcan@xxxxxxxxxxxx>
> ---
>  drivers/net/can/dev/skb.c     | 72 ++++++++++++++++++++++++++---------
>  include/linux/can/skb.h       | 23 ++++++++++-
>  include/uapi/linux/if_ether.h |  1 +
>  net/can/af_can.c              | 25 +++++++++++-
>  4 files changed, 101 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
> index adb413bdd734..f2ec20d80aba 100644
> --- a/drivers/net/can/dev/skb.c
> +++ b/drivers/net/can/dev/skb.c
> @@ -185,10 +185,24 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
>                 priv->echo_skb[idx] = NULL;
>         }
>  }
>  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;
>
>         skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
> @@ -198,20 +212,12 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
>
>                 return NULL;
>         }
>
>         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));
>
>         return skb;
>  }
> @@ -229,30 +235,55 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
>
>                 return NULL;
>         }
>
>         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));
>
>         /* set CAN FD flag by default */
>         (*cfd)->flags = CANFD_FDF;
>
>         return skb;
>  }
>  EXPORT_SYMBOL_GPL(alloc_canfd_skb);
>
> +struct sk_buff *alloc_canxl_skb(struct net_device *dev,
> +                               struct canxl_frame **cfx,
> +                               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;
> +
> +       *cfx = skb_put_zero(skb, CANXL_HDR_SIZE + data_len);
> +
> +       /* set CAN XL flag and length information by default */
> +       (*cfx)->flags = CANXL_XLF;
> +       (*cfx)->len = data_len;
> +
> +       return skb;
> +
> +out_error:
> +       *cfx = 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;
>
>         skb = alloc_can_skb(dev, cf);
> @@ -317,10 +348,15 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
>         case ETH_P_CANFD:
>                 if (!can_is_canfd_skb(skb))
>                         goto inval_skb;
>                 break;
>
> +       case ETH_P_CANXL:
> +               if (!can_is_canxl_skb(skb))
> +                       goto inval_skb;
> +               break;
> +
>         default:
>                 goto inval_skb;
>         }
>
>         if (!can_skb_headroom_valid(dev, skb)) {
> diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
> index ddffc2fc008c..01c01b1261fa 100644
> --- a/include/linux/can/skb.h
> +++ b/include/linux/can/skb.h
> @@ -28,10 +28,13 @@ unsigned int __must_check can_get_echo_skb(struct net_device *dev,
>  void can_free_echo_skb(struct net_device *dev, unsigned int idx,
>                        unsigned int *frame_len_ptr);
>  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 **cfx,
> +                               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);
>
>  /*
> @@ -112,15 +115,33 @@ static inline bool can_is_canfd_skb(const struct sk_buff *skb)
>
>         /* the CAN specific type of skb is identified by its data length */
>         return (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN);
>  }
>
> -/* get length element value from can[fd]_frame structure */
> +static inline bool can_is_canxl_skb(const struct sk_buff *skb)
> +{
> +       const struct canxl_frame *cfx = (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 + cfx->len)
> +               return false;
> +
> +       return cfx->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 *cfx = (struct canxl_frame *)skb->data;
>         const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;

Nitpick: what would be the acronyms for cfx and cfd? I thought that
cfd was for *C*AN-*FD* frame, and thus I would expect cxl instead of
cfx for *C*AN-*XL* frame.
On the contrary, if cfx stands for *C*AN *F*rame *X*L, then for
CAN-FD, the acronym should be cff (*C*AN *f*rame *F*D).


> +       if (can_is_canxl_skb(skb))
> +               return cfx->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)
> diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
> index d370165bc621..69e0457eb200 100644
> --- a/include/uapi/linux/if_ether.h
> +++ b/include/uapi/linux/if_ether.h
> @@ -136,10 +136,11 @@
>  #define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
>  #define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
>  #define ETH_P_LOCALTALK 0x0009         /* Localtalk pseudo type        */
>  #define ETH_P_CAN      0x000C          /* CAN: Controller Area Network */
>  #define ETH_P_CANFD    0x000D          /* CANFD: CAN flexible data rate*/
> +#define ETH_P_CANXL    0x000E          /* CANXL: eXtended frame Length */
>  #define ETH_P_PPPTALK  0x0010          /* Dummy type for Atalk over PPP*/
>  #define ETH_P_TR_802_2 0x0011          /* 802.2 frames                 */
>  #define ETH_P_MOBITEX  0x0015          /* Mobitex (kaz@xxxxxxxx)       */
>  #define ETH_P_CONTROL  0x0016          /* Card specific control frames */
>  #define ETH_P_IRDA     0x0017          /* Linux-IrDA                   */
> diff --git a/net/can/af_can.c b/net/can/af_can.c
> index 072a6a5c9dd1..9503ab10f9b8 100644
> --- a/net/can/af_can.c
> +++ b/net/can/af_can.c
> @@ -200,11 +200,13 @@ int can_send(struct sk_buff *skb, int loop)
>  {
>         struct sk_buff *newskb = NULL;
>         struct can_pkg_stats *pkg_stats = dev_net(skb->dev)->can.pkg_stats;
>         int err = -EINVAL;
>
> -       if (can_is_can_skb(skb)) {
> +       if (can_is_canxl_skb(skb)) {
> +               skb->protocol = htons(ETH_P_CANXL);
> +       } else if (can_is_can_skb(skb)) {
>                 skb->protocol = htons(ETH_P_CAN);
>         } else if (can_is_canfd_skb(skb)) {
>                 struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
>
>                 skb->protocol = htons(ETH_P_CANFD);
> @@ -700,10 +702,25 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
>
>         can_receive(skb, dev);
>         return NET_RX_SUCCESS;
>  }
>
> +static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
> +                    struct packet_type *pt, struct net_device *orig_dev)
> +{
> +       if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canxl_skb(skb)))) {
> +               pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n",
> +                            dev->type, skb->len);
> +
> +               kfree_skb(skb);
> +               return NET_RX_DROP;
> +       }
> +
> +       can_receive(skb, dev);
> +       return NET_RX_SUCCESS;
> +}
> +
>  /* af_can protocol functions */
>
>  /**
>   * can_proto_register - register CAN transport protocol
>   * @cp: pointer to CAN protocol structure
> @@ -824,10 +841,15 @@ static struct packet_type can_packet __read_mostly = {
>  static struct packet_type canfd_packet __read_mostly = {
>         .type = cpu_to_be16(ETH_P_CANFD),
>         .func = canfd_rcv,
>  };
>
> +static struct packet_type canxl_packet __read_mostly = {
> +       .type = cpu_to_be16(ETH_P_CANXL),
> +       .func = canxl_rcv,
> +};
> +
>  static const struct net_proto_family can_family_ops = {
>         .family = PF_CAN,
>         .create = can_create,
>         .owner  = THIS_MODULE,
>  };
> @@ -863,10 +885,11 @@ static __init int can_init(void)
>         if (err)
>                 goto out_sock;
>
>         dev_add_pack(&can_packet);
>         dev_add_pack(&canfd_packet);
> +       dev_add_pack(&canxl_packet);
>
>         return 0;
>
>  out_sock:
>         unregister_pernet_subsys(&can_pernet_ops);

Yours sincerely,
Vincent Mailhol



[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux