1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1216,6 +1216,7 @@ enum netdev_priv_flags {
IFF_LIVE_ADDR_CHANGE = 1<<20,
IFF_MACVLAN = 1<<21,
IFF_XMIT_DST_RELEASE_PERM = 1<<22,
+ IFF_NO_IP_ALIGN = 1<<23,
};
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2044,6 +2044,10 @@ static inline int pskb_trim(struct sk_bu
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
}
+extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
+ unsigned int length, gfp_t gfp);
+
+
/**
* pskb_trim_unique - remove end from a paged unique (not cloned) buffer
* @skb: buffer to alter
@@ -2170,16 +2174,6 @@ static inline struct sk_buff *dev_alloc_
}
-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
- unsigned int length, gfp_t gfp)
-{
- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
-
- if (NET_IP_ALIGN && skb)
- skb_reserve(skb, NET_IP_ALIGN);
- return skb;
-}
-
static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
unsigned int length)
{
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -25,6 +25,12 @@ menuconfig NET
if NET
+config ETHERNET_PACKET_MANGLE
+ bool
+ help
+ This option can be selected by phy drivers that need to mangle
+ packets going in or out of an ethernet device.
+
config WANT_COMPAT_NETLINK_MESSAGES
bool
help
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2607,10 +2607,20 @@ static int xmit_one(struct sk_buff *skb,
if (!list_empty(&ptype_all))
dev_queue_xmit_nit(skb, dev);
- len = skb->len;
- trace_net_dev_start_xmit(skb, dev);
- rc = netdev_start_xmit(skb, dev, txq, more);
- trace_net_dev_xmit(skb, rc, dev, len);
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
+ if (!dev->eth_mangle_tx ||
+ (skb = dev->eth_mangle_tx(dev, skb)) != NULL)
+#else
+ if (1)
+#endif
+ {
+ len = skb->len;
+ trace_net_dev_start_xmit(skb, dev);
+ rc = netdev_start_xmit(skb, dev, txq, more);
+ trace_net_dev_xmit(skb, rc, dev, len);
+ } else {
+ rc = NETDEV_TX_OK;
+ }
return rc;
}
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -63,6 +63,7 @@
#include <linux/errqueue.h>
#include <linux/prefetch.h>
#include <linux/if_vlan.h>
+#include <linux/if.h>
#include <net/protocol.h>
#include <net/dst.h>
@@ -451,6 +452,22 @@ struct sk_buff *__netdev_alloc_skb(struc
}
EXPORT_SYMBOL(__netdev_alloc_skb);
+struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
+ unsigned int length, gfp_t gfp)
+{
+ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
+
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
+ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
+ return skb;
+#endif
+
+ if (NET_IP_ALIGN && skb)
+ skb_reserve(skb, NET_IP_ALIGN);
+ return skb;
+}
+EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
+
void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
int size, unsigned int truesize)
{
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -188,6 +188,12 @@ __be16 eth_type_trans(struct sk_buff *sk
const struct ethhdr *eth;
skb->dev = dev;
+
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
+ if (dev->eth_mangle_rx)
+ dev->eth_mangle_rx(dev, skb);
+#endif
+
skb_reset_mac_header(skb);
skb_pull_inline(skb, ETH_HLEN);
eth = eth_hdr(skb);
|