Oliver Hartkopp wrote:
> Wolfgang Grandegger wrote:
>> OK, interesting, then prepare a rfc patch and post it on the netdev ml.
>> For use (socketcan) it's a minor issue but a general solution would be
>> nice, indeed.
>
> Yes. Will do.
>
> The return value of the netdevice is processed in dev_hard_start_xmit() in
> net/core/dev.c .
>
> I first need to look, what could be the best way to pass the error up the
> specific socket from there.
Hi all,
to get an error code to the application i needed to get into dev_queue_xmit()
that's called from the several network protocols.
I added a netdevice function that offers the skb check.
Please have a look:
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index d0ec178..6a19a33 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -1017,6 +1017,7 @@ static const struct net_device_ops at91_netdev_ops = {
.ndo_open = at91_open,
.ndo_stop = at91_close,
.ndo_start_xmit = at91_start_xmit,
+ .ndo_validate_skb = can_validate_skb,
};
static int __init at91_can_probe(struct platform_device *pdev)
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 0ec1524..646f326 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -608,6 +608,7 @@ static const struct net_device_ops bfin_can_netdev_ops = {
.ndo_open = bfin_can_open,
.ndo_stop = bfin_can_close,
.ndo_start_xmit = bfin_can_start_xmit,
+ .ndo_validate_skb = can_validate_skb,
};
static int __devinit bfin_can_probe(struct platform_device *pdev)
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 9c5a153..773926a 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -925,6 +925,7 @@ static const struct net_device_ops mcp251x_netdev_ops = {
.ndo_open = mcp251x_open,
.ndo_stop = mcp251x_stop,
.ndo_start_xmit = mcp251x_hard_start_xmit,
+ .ndo_validate_skb = can_validate_skb,
};
static int __devinit mcp251x_can_probe(struct spi_device *spi)
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
index 07346f8..280448e 100644
--- a/drivers/net/can/mscan/mscan.c
+++ b/drivers/net/can/mscan/mscan.c
@@ -590,6 +590,7 @@ static const struct net_device_ops mscan_netdev_ops = {
.ndo_open = mscan_open,
.ndo_stop = mscan_close,
.ndo_start_xmit = mscan_start_xmit,
+ .ndo_validate_skb = can_validate_skb,
};
int register_mscandev(struct net_device *dev, int clock_src)
diff --git a/drivers/net/can/sja1000/sja1000.c
b/drivers/net/can/sja1000/sja1000.c
index 542a4f7..a724223 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -582,6 +582,7 @@ static const struct net_device_ops sja1000_netdev_ops = {
.ndo_open = sja1000_open,
.ndo_stop = sja1000_close,
.ndo_start_xmit = sja1000_start_xmit,
+ .ndo_validate_skb = can_validate_skb,
};
int register_sja1000dev(struct net_device *dev)
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 5c993c2..cd8e4fc 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -850,6 +850,7 @@ static const struct net_device_ops ti_hecc_netdev_ops = {
.ndo_open = ti_hecc_open,
.ndo_stop = ti_hecc_close,
.ndo_start_xmit = ti_hecc_xmit,
+ .ndo_validate_skb = can_validate_skb,
};
static int ti_hecc_probe(struct platform_device *pdev)
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index efbb05c..03a756a 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -905,6 +905,7 @@ static const struct net_device_ops ems_usb_netdev_ops = {
.ndo_open = ems_usb_open,
.ndo_stop = ems_usb_close,
.ndo_start_xmit = ems_usb_start_xmit,
+ .ndo_validate_skb = can_validate_skb,
};
static struct can_bittiming_const ems_usb_bittiming_const = {
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 80ac563..cb00b03 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -47,6 +47,7 @@
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/can.h>
+#include <linux/can/dev.h>
#include <net/rtnetlink.h>
static __initdata const char banner[] =
@@ -130,6 +131,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct
net_device *dev)
static const struct net_device_ops vcan_netdev_ops = {
.ndo_start_xmit = vcan_tx,
+ .ndo_validate_skb = can_validate_skb,
};
static void vcan_setup(struct net_device *dev)
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 3db7767..b70d6f3 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -77,6 +77,16 @@ void can_put_echo_skb(struct sk_buff *skb, struct
net_device *dev,
void can_get_echo_skb(struct net_device *dev, unsigned int idx);
void can_free_echo_skb(struct net_device *dev, unsigned int idx);
+static inline int can_validate_skb(struct sk_buff *skb)
+{
+ struct can_frame *cf = (struct can_frame *)skb->data;
+
+ if (unlikely(skb->len != sizeof(struct can_frame) || cf->can_dlc > 8))
+ return 1;
+
+ return 0;
+}
+
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
struct sk_buff *alloc_can_err_skb(struct net_device *dev,
struct can_frame **cf);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a3fccc8..a3f4794 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -571,6 +571,9 @@ struct netdev_queue {
* int (*ndo_validate_addr)(struct net_device *dev);
* Test if Media Access Control address is valid for the device.
*
+ * int (*ndo_validate_skb)(struct sk_buff *skb);
+ * Test if the given skb content is valid for this device.
+ *
* int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
* Called when a user request an ioctl which can't be handled by
* the generic interface code. If not defined ioctl's return
@@ -633,6 +636,10 @@ struct net_device_ops {
void *addr);
#define HAVE_VALIDATE_ADDR
int (*ndo_validate_addr)(struct net_device *dev);
+
+#define HAVE_VALIDATE_SKB
+ int (*ndo_validate_skb)(struct sk_buff *skb);
+
#define HAVE_PRIVATE_IOCTL
int (*ndo_do_ioctl)(struct net_device *dev,
struct ifreq *ifr, int cmd);
diff --git a/net/core/dev.c b/net/core/dev.c
index be9924f..9de3484 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2002,6 +2002,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb,
struct Qdisc *q,
int dev_queue_xmit(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
+ const struct net_device_ops *ops = dev->netdev_ops;
struct netdev_queue *txq;
struct Qdisc *q;
int rc = -ENOMEM;
@@ -2034,6 +2035,14 @@ int dev_queue_xmit(struct sk_buff *skb)
goto out_kfree_skb;
}
+ /* If the device offers a function to validate the skb content, let
+ * it check the skb and return an error to the caller if it fails.
+ */
+ if (ops->ndo_validate_skb && ops->ndo_validate_skb(skb)) {
+ rc = -EINVAL;
+ goto out_kfree_skb;
+ }
+
gso:
/* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core