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

Reply via email to