summaryrefslogtreecommitdiff
path: root/drivers/net/can/dev/skb.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2022-06-27 11:47:18 +0100
committerDavid S. Miller <davem@davemloft.net>2022-06-27 11:47:18 +0100
commit9dd094ee142b8dfd649df2d43c71a2ac7536b9ea (patch)
tree8ad473d3bc0c6f93bc681b1abc8ea7654d69b474 /drivers/net/can/dev/skb.c
parentc83bc86a0596f88958a4279e2558e65c7332169a (diff)
parentc3d396120d68c40cdf2a2da70eff3bf8806f0ff5 (diff)
Merge tag 'linux-can-next-for-5.20-20220625' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
Marc Kleine-Budde says: ==================== pull-request: can-next 2022-06-25 this is a pull request of 22 patches for net-next/master. The first 2 patches target the xilinx driver. Srinivas Neeli's patch adds Transmitter Delay Compensation (TDC) support, a patch by me fixes a typo. The next patch is by me and fixes a typo in the m_can driver. Another patch by me allows the configuration of fixed bit rates without need for do_set_bittiming callback. The following 7 patches are by Vincent Mailhol and refactor the can-dev module and Kbuild, de-inline the can_dropped_invalid_skb() function, which has grown over the time, and drop outgoing skbs if the controller is in listen only mode. Max Staudt's patch fixes a reference in the networking/can.rst documentation. Vincent Mailhol provides 2 patches with cleanups for the etas_es58x driver. Conor Dooley adds bindings for the mpfs-can to the PolarFire SoC dtsi. Another patch by me allows the configuration of fixed data bit rates without need for do_set_data_bittiming callback. The last 5 patches are by Frank Jungclaus. They prepare the esd_usb driver to add support for the the CAN-USB/3 device in a later series. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/can/dev/skb.c')
-rw-r--r--drivers/net/can/dev/skb.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 61660248c69e..8bb62dd864c8 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -5,6 +5,14 @@
*/
#include <linux/can/dev.h>
+#include <linux/can/netlink.h>
+#include <linux/module.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
*
@@ -252,3 +260,67 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
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_headroom_valid(struct net_device *dev, struct sk_buff *skb)
+{
+ /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
+ if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
+ return false;
+
+ /* af_packet does not apply CAN skb specific settings */
+ if (skb->ip_summed == CHECKSUM_NONE) {
+ /* init headroom */
+ can_skb_prv(skb)->ifindex = dev->ifindex;
+ can_skb_prv(skb)->skbcnt = 0;
+
+ 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);
+ }
+
+ 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)
+{
+ const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+ struct can_priv *priv = netdev_priv(dev);
+
+ if (skb->protocol == htons(ETH_P_CAN)) {
+ if (unlikely(skb->len != CAN_MTU ||
+ cfd->len > CAN_MAX_DLEN))
+ goto inval_skb;
+ } else if (skb->protocol == htons(ETH_P_CANFD)) {
+ if (unlikely(skb->len != CANFD_MTU ||
+ cfd->len > CANFD_MAX_DLEN))
+ goto inval_skb;
+ } else {
+ goto inval_skb;
+ }
+
+ if (!can_skb_headroom_valid(dev, skb)) {
+ goto inval_skb;
+ } else if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ netdev_info_once(dev,
+ "interface in listen only mode, dropping skb\n");
+ goto inval_skb;
+ }
+
+ return false;
+
+inval_skb:
+ kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return true;
+}
+EXPORT_SYMBOL_GPL(can_dropped_invalid_skb);