// SPDX-License-Identifier: GPL-2.0-only/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix * Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> */ #include <linux/can/dev.h>#include <linux/module.h>#include <net/can.h> #define MOD_DESC "CAN device driver interface" MODULE_DESCRIPTION(MOD_DESC);MODULE_LICENSE("GPL v2");MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); /* Local echo of CAN messages * * CAN network devices *should* support a local echo functionality * (see Documentation/networking/can.rst). To test the handling of CAN * interfaces that do not support the local echo both driver types are * implemented. In the case that the driver does not support the echo * the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core * to perform the echo as a fallback solution. */void can_flush_echo_skb(struct net_device *dev){ struct can_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; int i; for (i = 0; i < priv->echo_skb_max; i++) { if (priv->echo_skb[i]) { kfree_skb(priv->echo_skb[i]); priv->echo_skb[i] = NULL; stats->tx_dropped++; stats->tx_aborted_errors++; } }} /* Put the skb on the stack to be looped backed locally lateron * * The function is typically called in the start_xmit function * of the device driver. The driver must protect access to * priv->echo_skb, if necessary. */int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, unsigned int idx, unsigned int frame_len){ struct can_priv *priv = netdev_priv(dev); struct can_skb_ext *csx; if (idx >= priv->echo_skb_max) { netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n", __func__, idx, priv->echo_skb_max); return -EINVAL; } /* check flag whether this packet has to be looped back */ if (!(dev->flags & IFF_ECHO) || (skb->protocol != htons(ETH_P_CAN) && skb->protocol != htons(ETH_P_CANFD) && skb->protocol != htons(ETH_P_CANXL))) { kfree_skb(skb); return 0; } if (!priv->echo_skb[idx]) { skb = can_create_echo_skb(skb); if (!skb) return -ENOMEM; /* make settings for echo to reduce code in irq context */ skb->ip_summed = CHECKSUM_UNNECESSARY; skb->dev = dev; /* save frame_len to reuse it when transmission is completed */ csx = can_skb_ext_find(skb); if (csx) csx->can_framelen = frame_len; if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_tx_timestamp(skb); /* save this skb for tx interrupt echo handling */ priv->echo_skb[idx] = skb; } else { /* locking problem with netif_stop_queue() ?? */ netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx); kfree_skb(skb); return -EBUSY; } return 0;}EXPORT_SYMBOL_GPL(can_put_echo_skb); struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, unsigned int *len_ptr, unsigned int *frame_len_ptr){ struct can_priv *priv = netdev_priv(dev); if (idx >= priv->echo_skb_max) { netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n", __func__, idx, priv->echo_skb_max); return NULL; } if (priv->echo_skb[idx]) { /* Using "struct canfd_frame::len" for the frame * length is supported on both CAN and CANFD frames. */ struct sk_buff *skb = priv->echo_skb[idx]; struct can_skb_ext *csx; if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) skb_tstamp_tx(skb, skb_hwtstamps(skb)); /* get the real payload length for netdev statistics */ *len_ptr = can_skb_get_data_len(skb); if (frame_len_ptr) { csx = can_skb_ext_find(skb); if (csx) *frame_len_ptr = csx->can_framelen; else *frame_len_ptr = 0; } priv->echo_skb[idx] = NULL; if (skb->pkt_type == PACKET_LOOPBACK) { skb->pkt_type = PACKET_BROADCAST; } else { dev_consume_skb_any(skb); return NULL; } return skb; } return NULL;} /* Get the skb from the stack and loop it back locally * * The function is typically called when the TX done interrupt * is handled in the device driver. The driver must protect * access to priv->echo_skb, if necessary. */unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx, unsigned int *frame_len_ptr){ struct sk_buff *skb; unsigned int len; skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr); if (!skb) return 0; skb_get(skb); if (netif_rx(skb) == NET_RX_SUCCESS) dev_consume_skb_any(skb); else dev_kfree_skb_any(skb); return len;}EXPORT_SYMBOL_GPL(can_get_echo_skb); /* Remove the skb from the stack and free it. * * The function is typically called when TX failed. */void can_free_echo_skb(struct net_device *dev, unsigned int idx, unsigned int *frame_len_ptr){ struct can_priv *priv = netdev_priv(dev); if (idx >= priv->echo_skb_max) { netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n", __func__, idx, priv->echo_skb_max); return; } if (priv->echo_skb[idx]) { struct sk_buff *skb = priv->echo_skb[idx]; struct can_skb_ext *csx; if (frame_len_ptr) { csx = can_skb_ext_find(skb); if (csx) *frame_len_ptr = csx->can_framelen; else *frame_len_ptr = 0; } dev_kfree_skb_any(skb); priv->echo_skb[idx] = NULL; }}EXPORT_SYMBOL_GPL(can_free_echo_skb); /* fill common values for CAN sk_buffs */static void init_can_skb(struct sk_buff *skb){ skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY;} struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf){ struct sk_buff *skb; struct can_skb_ext *csx; skb = netdev_alloc_skb(dev, sizeof(struct can_frame)); if (unlikely(!skb)) goto out_error_cc; csx = can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto out_error_cc; } skb->protocol = htons(ETH_P_CAN); init_can_skb(skb); csx->can_iif = dev->ifindex; *cf = skb_put_zero(skb, sizeof(struct can_frame)); return skb; out_error_cc: *cf = NULL; return NULL;}EXPORT_SYMBOL_GPL(alloc_can_skb); struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct canfd_frame **cfd){ struct sk_buff *skb; struct can_skb_ext *csx; skb = netdev_alloc_skb(dev, sizeof(struct canfd_frame)); if (unlikely(!skb)) goto out_error_fd; csx = can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto out_error_fd; } skb->protocol = htons(ETH_P_CANFD); init_can_skb(skb); csx->can_iif = dev->ifindex; *cfd = skb_put_zero(skb, sizeof(struct canfd_frame)); /* set CAN FD flag by default */ (*cfd)->flags = CANFD_FDF; return skb; out_error_fd: *cfd = NULL; return NULL;}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; struct can_skb_ext *csx; if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN) goto out_error_xl; skb = netdev_alloc_skb(dev, CANXL_HDR_SIZE + data_len); if (unlikely(!skb)) goto out_error_xl; csx = can_skb_ext_add(skb); if (!csx) { kfree_skb(skb); goto out_error_xl; } skb->protocol = htons(ETH_P_CANXL); init_can_skb(skb); csx->can_iif = 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_xl: *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; skb = alloc_can_skb(dev, cf); if (unlikely(!skb)) return NULL; (*cf)->can_id = CAN_ERR_FLAG; (*cf)->len = CAN_ERR_DLC; return skb;}EXPORT_SYMBOL_GPL(alloc_can_err_skb); /* Check for outgoing skbs that have not been created by the CAN subsystem */static bool can_skb_init_valid(struct net_device *dev, struct sk_buff *skb){ struct can_skb_ext *csx = can_skb_ext_find(skb); /* af_packet does not apply CAN skb specific settings */ if (skb->ip_summed == CHECKSUM_NONE || !csx) { /* init CAN skb content */ if (!csx) { csx = can_skb_ext_add(skb); if (!csx) return false; } csx->can_iif = dev->ifindex; skb->ip_summed = CHECKSUM_UNNECESSARY; /* perform proper loopback on capable devices */ if (dev->flags & IFF_ECHO) skb->pkt_type = PACKET_LOOPBACK; else skb->pkt_type = PACKET_HOST; skb_reset_mac_header(skb); skb_reset_network_header(skb); skb_reset_transport_header(skb); /* set CANFD_FDF flag for CAN FD frames */ if (can_is_canfd_skb(skb)) { struct canfd_frame *cfd; cfd = (struct canfd_frame *)skb->data; cfd->flags |= CANFD_FDF; } } return true;} /* Drop a given socketbuffer if it does not contain a valid CAN frame. */bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb){ switch (ntohs(skb->protocol)) { case ETH_P_CAN: if (!can_is_can_skb(skb)) goto inval_skb; break; 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_init_valid(dev, skb)) goto inval_skb; return false; inval_skb: kfree_skb(skb); dev->stats.tx_dropped++; return true;}EXPORT_SYMBOL_GPL(can_dropped_invalid_skb);
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
*/
#include <linux/can/dev.h>
#include <linux/module.h>
#include <net/can.h>
#define MOD_DESC "CAN device driver interface"
MODULE_DESCRIPTION(MOD_DESC);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
/* Local echo of CAN messages
*
* CAN network devices *should* support a local echo functionality
* (see Documentation/networking/can.rst). To test the handling of CAN
* interfaces that do not support the local echo both driver types are
* implemented. In the case that the driver does not support the echo
* the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
* to perform the echo as a fallback solution.
*/
void can_flush_echo_skb(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
int i;
for (i = 0; i < priv->echo_skb_max; i++) {
if (priv->echo_skb[i]) {
kfree_skb(priv->echo_skb[i]);
priv->echo_skb[i] = NULL;
stats->tx_dropped++;
stats->tx_aborted_errors++;
}
}
}
/* Put the skb on the stack to be looped backed locally lateron
*
* The function is typically called in the start_xmit function
* of the device driver. The driver must protect access to
* priv->echo_skb, if necessary.
*/
int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
unsigned int idx, unsigned int frame_len)
{
struct can_priv *priv = netdev_priv(dev);
struct can_skb_ext *csx;
if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
return -EINVAL;
}
/* check flag whether this packet has to be looped back */
if (!(dev->flags & IFF_ECHO) ||
(skb->protocol != htons(ETH_P_CAN) &&
skb->protocol != htons(ETH_P_CANFD) &&
skb->protocol != htons(ETH_P_CANXL))) {
kfree_skb(skb);
return 0;
}
if (!priv->echo_skb[idx]) {
skb = can_create_echo_skb(skb);
if (!skb)
return -ENOMEM;
/* make settings for echo to reduce code in irq context */
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->dev = dev;
/* save frame_len to reuse it when transmission is completed */
csx = can_skb_ext_find(skb);
if (csx)
csx->can_framelen = frame_len;
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
skb_tx_timestamp(skb);
/* save this skb for tx interrupt echo handling */
priv->echo_skb[idx] = skb;
} else {
/* locking problem with netif_stop_queue() ?? */
netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
kfree_skb(skb);
return -EBUSY;
}
return 0;
}
EXPORT_SYMBOL_GPL(can_put_echo_skb);
struct sk_buff *
__can_get_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *len_ptr, unsigned int *frame_len_ptr)
{
struct can_priv *priv = netdev_priv(dev);
if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
return NULL;
}
if (priv->echo_skb[idx]) {
/* Using "struct canfd_frame::len" for the frame
* length is supported on both CAN and CANFD frames.
*/
struct sk_buff *skb = priv->echo_skb[idx];
struct can_skb_ext *csx;
if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)
skb_tstamp_tx(skb, skb_hwtstamps(skb));
/* get the real payload length for netdev statistics */
*len_ptr = can_skb_get_data_len(skb);
if (frame_len_ptr) {
csx = can_skb_ext_find(skb);
if (csx)
*frame_len_ptr = csx->can_framelen;
else
*frame_len_ptr = 0;
}
priv->echo_skb[idx] = NULL;
if (skb->pkt_type == PACKET_LOOPBACK) {
skb->pkt_type = PACKET_BROADCAST;
} else {
dev_consume_skb_any(skb);
return NULL;
}
return skb;
}
return NULL;
}
/* Get the skb from the stack and loop it back locally
*
* The function is typically called when the TX done interrupt
* is handled in the device driver. The driver must protect
* access to priv->echo_skb, if necessary.
*/
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr)
{
struct sk_buff *skb;
unsigned int len;
skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
if (!skb)
return 0;
skb_get(skb);
if (netif_rx(skb) == NET_RX_SUCCESS)
dev_consume_skb_any(skb);
else
dev_kfree_skb_any(skb);
return len;
}
EXPORT_SYMBOL_GPL(can_get_echo_skb);
/* Remove the skb from the stack and free it.
*
* The function is typically called when TX failed.
*/
void can_free_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr)
{
struct can_priv *priv = netdev_priv(dev);
if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
return;
}
if (priv->echo_skb[idx]) {
struct sk_buff *skb = priv->echo_skb[idx];
struct can_skb_ext *csx;
if (frame_len_ptr) {
csx = can_skb_ext_find(skb);
if (csx)
*frame_len_ptr = csx->can_framelen;
else
*frame_len_ptr = 0;
}
dev_kfree_skb_any(skb);
priv->echo_skb[idx] = NULL;
}
}
EXPORT_SYMBOL_GPL(can_free_echo_skb);
/* fill common values for CAN sk_buffs */
static void init_can_skb(struct sk_buff *skb)
{
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
{
struct sk_buff *skb;
struct can_skb_ext *csx;
skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
if (unlikely(!skb))
goto out_error_cc;
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
goto out_error_cc;
}
skb->protocol = htons(ETH_P_CAN);
init_can_skb(skb);
csx->can_iif = dev->ifindex;
*cf = skb_put_zero(skb, sizeof(struct can_frame));
return skb;
out_error_cc:
*cf = NULL;
return NULL;
}
EXPORT_SYMBOL_GPL(alloc_can_skb);
struct sk_buff *alloc_canfd_skb(struct net_device *dev,
struct canfd_frame **cfd)
{
struct sk_buff *skb;
struct can_skb_ext *csx;
skb = netdev_alloc_skb(dev, sizeof(struct canfd_frame));
if (unlikely(!skb))
goto out_error_fd;
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
goto out_error_fd;
}
skb->protocol = htons(ETH_P_CANFD);
init_can_skb(skb);
csx->can_iif = dev->ifindex;
*cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
/* set CAN FD flag by default */
(*cfd)->flags = CANFD_FDF;
return skb;
out_error_fd:
*cfd = NULL;
return NULL;
}
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;
struct can_skb_ext *csx;
if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN)
goto out_error_xl;
skb = netdev_alloc_skb(dev, CANXL_HDR_SIZE + data_len);
if (unlikely(!skb))
goto out_error_xl;
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
goto out_error_xl;
}
skb->protocol = htons(ETH_P_CANXL);
init_can_skb(skb);
csx->can_iif = 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_xl:
*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;
skb = alloc_can_skb(dev, cf);
if (unlikely(!skb))
return NULL;
(*cf)->can_id = CAN_ERR_FLAG;
(*cf)->len = CAN_ERR_DLC;
return skb;
}
EXPORT_SYMBOL_GPL(alloc_can_err_skb);
/* Check for outgoing skbs that have not been created by the CAN subsystem */
static bool can_skb_init_valid(struct net_device *dev, struct sk_buff *skb)
{
struct can_skb_ext *csx = can_skb_ext_find(skb);
/* af_packet does not apply CAN skb specific settings */
if (skb->ip_summed == CHECKSUM_NONE || !csx) {
/* init CAN skb content */
if (!csx) {
csx = can_skb_ext_add(skb);
if (!csx)
return false;
}
csx->can_iif = dev->ifindex;
skb->ip_summed = CHECKSUM_UNNECESSARY;
/* perform proper loopback on capable devices */
if (dev->flags & IFF_ECHO)
skb->pkt_type = PACKET_LOOPBACK;
else
skb->pkt_type = PACKET_HOST;
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
/* set CANFD_FDF flag for CAN FD frames */
if (can_is_canfd_skb(skb)) {
struct canfd_frame *cfd;
cfd = (struct canfd_frame *)skb->data;
cfd->flags |= CANFD_FDF;
}
}
return true;
}
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
{
switch (ntohs(skb->protocol)) {
case ETH_P_CAN:
if (!can_is_can_skb(skb))
goto inval_skb;
break;
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_init_valid(dev, skb))
goto inval_skb;
return false;
inval_skb:
kfree_skb(skb);
dev->stats.tx_dropped++;
return true;
}
EXPORT_SYMBOL_GPL(can_dropped_invalid_skb);