linux/include/linux/can/skb.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
   2/*
   3 * linux/can/skb.h
   4 *
   5 * Definitions for the CAN network socket buffer
   6 *
   7 * Copyright (C) 2012 Oliver Hartkopp <socketcan@hartkopp.net>
   8 *
   9 */
  10
  11#ifndef _CAN_SKB_H
  12#define _CAN_SKB_H
  13
  14#include <linux/types.h>
  15#include <linux/skbuff.h>
  16#include <linux/can.h>
  17#include <net/sock.h>
  18
  19void can_flush_echo_skb(struct net_device *dev);
  20int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
  21                     unsigned int idx, unsigned int frame_len);
  22struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx,
  23                                   u8 *len_ptr, unsigned int *frame_len_ptr);
  24unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
  25                              unsigned int *frame_len_ptr);
  26void can_free_echo_skb(struct net_device *dev, unsigned int idx,
  27                       unsigned int *frame_len_ptr);
  28struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
  29struct sk_buff *alloc_canfd_skb(struct net_device *dev,
  30                                struct canfd_frame **cfd);
  31struct sk_buff *alloc_can_err_skb(struct net_device *dev,
  32                                  struct can_frame **cf);
  33
  34/*
  35 * The struct can_skb_priv is used to transport additional information along
  36 * with the stored struct can(fd)_frame that can not be contained in existing
  37 * struct sk_buff elements.
  38 * N.B. that this information must not be modified in cloned CAN sk_buffs.
  39 * To modify the CAN frame content or the struct can_skb_priv content
  40 * skb_copy() needs to be used instead of skb_clone().
  41 */
  42
  43/**
  44 * struct can_skb_priv - private additional data inside CAN sk_buffs
  45 * @ifindex:    ifindex of the first interface the CAN frame appeared on
  46 * @skbcnt:     atomic counter to have an unique id together with skb pointer
  47 * @frame_len:  length of CAN frame in data link layer
  48 * @cf:         align to the following CAN frame at skb->data
  49 */
  50struct can_skb_priv {
  51        int ifindex;
  52        int skbcnt;
  53        unsigned int frame_len;
  54        struct can_frame cf[];
  55};
  56
  57static inline struct can_skb_priv *can_skb_prv(struct sk_buff *skb)
  58{
  59        return (struct can_skb_priv *)(skb->head);
  60}
  61
  62static inline void can_skb_reserve(struct sk_buff *skb)
  63{
  64        skb_reserve(skb, sizeof(struct can_skb_priv));
  65}
  66
  67static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk)
  68{
  69        /* If the socket has already been closed by user space, the
  70         * refcount may already be 0 (and the socket will be freed
  71         * after the last TX skb has been freed). So only increase
  72         * socket refcount if the refcount is > 0.
  73         */
  74        if (sk && refcount_inc_not_zero(&sk->sk_refcnt)) {
  75                skb->destructor = sock_efree;
  76                skb->sk = sk;
  77        }
  78}
  79
  80/*
  81 * returns an unshared skb owned by the original sock to be echo'ed back
  82 */
  83static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
  84{
  85        struct sk_buff *nskb;
  86
  87        nskb = skb_clone(skb, GFP_ATOMIC);
  88        if (unlikely(!nskb)) {
  89                kfree_skb(skb);
  90                return NULL;
  91        }
  92
  93        can_skb_set_owner(nskb, skb->sk);
  94        consume_skb(skb);
  95        return nskb;
  96}
  97
  98/* Check for outgoing skbs that have not been created by the CAN subsystem */
  99static inline bool can_skb_headroom_valid(struct net_device *dev,
 100                                          struct sk_buff *skb)
 101{
 102        /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
 103        if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
 104                return false;
 105
 106        /* af_packet does not apply CAN skb specific settings */
 107        if (skb->ip_summed == CHECKSUM_NONE) {
 108                /* init headroom */
 109                can_skb_prv(skb)->ifindex = dev->ifindex;
 110                can_skb_prv(skb)->skbcnt = 0;
 111
 112                skb->ip_summed = CHECKSUM_UNNECESSARY;
 113
 114                /* perform proper loopback on capable devices */
 115                if (dev->flags & IFF_ECHO)
 116                        skb->pkt_type = PACKET_LOOPBACK;
 117                else
 118                        skb->pkt_type = PACKET_HOST;
 119
 120                skb_reset_mac_header(skb);
 121                skb_reset_network_header(skb);
 122                skb_reset_transport_header(skb);
 123        }
 124
 125        return true;
 126}
 127
 128/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
 129static inline bool can_dropped_invalid_skb(struct net_device *dev,
 130                                          struct sk_buff *skb)
 131{
 132        const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
 133
 134        if (skb->protocol == htons(ETH_P_CAN)) {
 135                if (unlikely(skb->len != CAN_MTU ||
 136                             cfd->len > CAN_MAX_DLEN))
 137                        goto inval_skb;
 138        } else if (skb->protocol == htons(ETH_P_CANFD)) {
 139                if (unlikely(skb->len != CANFD_MTU ||
 140                             cfd->len > CANFD_MAX_DLEN))
 141                        goto inval_skb;
 142        } else
 143                goto inval_skb;
 144
 145        if (!can_skb_headroom_valid(dev, skb))
 146                goto inval_skb;
 147
 148        return false;
 149
 150inval_skb:
 151        kfree_skb(skb);
 152        dev->stats.tx_dropped++;
 153        return true;
 154}
 155
 156static inline bool can_is_canfd_skb(const struct sk_buff *skb)
 157{
 158        /* the CAN specific type of skb is identified by its data length */
 159        return skb->len == CANFD_MTU;
 160}
 161
 162#endif /* !_CAN_SKB_H */
 163