diff options
author | David S. Miller <davem@davemloft.net> | 2013-12-31 16:23:35 -0500 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2014-02-15 19:20:09 +0000 |
commit | 31da359741b539fb236d5781b46ee7c5c6d8f14c (patch) | |
tree | 2f74272eb5ece8dd5d70faa59fce3fa9c266d6cc /include | |
parent | 5299412590050caf9b8192a5914a54be792ff7ee (diff) |
vlan: Fix header ops passthru when doing TX VLAN offload.
[ Upstream commit 2205369a314e12fcec4781cc73ac9c08fc2b47de ]
When the vlan code detects that the real device can do TX VLAN offloads
in hardware, it tries to arrange for the real device's header_ops to
be invoked directly.
But it does so illegally, by simply hooking the real device's
header_ops up to the VLAN device.
This doesn't work because we will end up invoking a set of header_ops
routines which expect a device type which matches the real device, but
will see a VLAN device instead.
Fix this by providing a pass-thru set of header_ops which will arrange
to pass the proper real device instead.
To facilitate this add a dev_rebuild_header(). There are
implementations which provide a ->cache and ->create but not a
->rebuild (f.e. PLIP). So we need a helper function just like
dev_hard_header() to avoid crashes.
Use this helper in the one existing place where the
header_ops->rebuild was being invoked, the neighbour code.
With lots of help from Florian Westphal.
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/netdevice.h | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8c43fd17d140..4b04097c748c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1719,6 +1719,15 @@ static inline int dev_parse_header(const struct sk_buff *skb, return dev->header_ops->parse(skb, haddr); } +static inline int dev_rebuild_header(struct sk_buff *skb) +{ + const struct net_device *dev = skb->dev; + + if (!dev->header_ops || !dev->header_ops->rebuild) + return 0; + return dev->header_ops->rebuild(skb); +} + typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); static inline int unregister_gifconf(unsigned int family) |