| 1 | --- a/include/linux/netdevice.h |
| 2 | +++ b/include/linux/netdevice.h |
| 3 | @@ -1102,6 +1102,11 @@ struct net_device { |
| 4 | const struct net_device_ops *netdev_ops; |
| 5 | const struct ethtool_ops *ethtool_ops; |
| 6 | |
| 7 | +#ifdef CONFIG_ETHERNET_PACKET_MANGLE |
| 8 | + void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); |
| 9 | + struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); |
| 10 | +#endif |
| 11 | + |
| 12 | /* Hardware header description */ |
| 13 | const struct header_ops *header_ops; |
| 14 | |
| 15 | @@ -1158,6 +1163,9 @@ struct net_device { |
| 16 | void *ax25_ptr; /* AX.25 specific data */ |
| 17 | struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data, |
| 18 | assign before registering */ |
| 19 | +#ifdef CONFIG_ETHERNET_PACKET_MANGLE |
| 20 | + void *phy_ptr; /* PHY device specific data */ |
| 21 | +#endif |
| 22 | |
| 23 | /* |
| 24 | * Cache lines mostly used on receive path (including eth_type_trans()) |
| 25 | --- a/include/linux/if.h |
| 26 | +++ b/include/linux/if.h |
| 27 | @@ -83,6 +83,7 @@ |
| 28 | #define IFF_SUPP_NOFCS 0x80000 /* device supports sending custom FCS */ |
| 29 | #define IFF_LIVE_ADDR_CHANGE 0x100000 /* device supports hardware address |
| 30 | * change when it's running */ |
| 31 | +#define IFF_NO_IP_ALIGN 0x200000 /* do not ip-align allocated rx pkts */ |
| 32 | |
| 33 | |
| 34 | #define IF_GET_IFACE 0x0001 /* for querying only */ |
| 35 | --- a/include/linux/skbuff.h |
| 36 | +++ b/include/linux/skbuff.h |
| 37 | @@ -1653,6 +1653,10 @@ static inline int pskb_trim(struct sk_bu |
| 38 | return (len < skb->len) ? __pskb_trim(skb, len) : 0; |
| 39 | } |
| 40 | |
| 41 | +extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, |
| 42 | + unsigned int length, gfp_t gfp); |
| 43 | + |
| 44 | + |
| 45 | /** |
| 46 | * pskb_trim_unique - remove end from a paged unique (not cloned) buffer |
| 47 | * @skb: buffer to alter |
| 48 | @@ -1755,16 +1759,6 @@ static inline struct sk_buff *dev_alloc_ |
| 49 | } |
| 50 | |
| 51 | |
| 52 | -static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, |
| 53 | - unsigned int length, gfp_t gfp) |
| 54 | -{ |
| 55 | - struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); |
| 56 | - |
| 57 | - if (NET_IP_ALIGN && skb) |
| 58 | - skb_reserve(skb, NET_IP_ALIGN); |
| 59 | - return skb; |
| 60 | -} |
| 61 | - |
| 62 | static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, |
| 63 | unsigned int length) |
| 64 | { |
| 65 | --- a/net/Kconfig |
| 66 | +++ b/net/Kconfig |
| 67 | @@ -23,6 +23,12 @@ menuconfig NET |
| 68 | |
| 69 | if NET |
| 70 | |
| 71 | +config ETHERNET_PACKET_MANGLE |
| 72 | + bool |
| 73 | + help |
| 74 | + This option can be selected by phy drivers that need to mangle |
| 75 | + packets going in or out of an ethernet device. |
| 76 | + |
| 77 | config WANT_COMPAT_NETLINK_MESSAGES |
| 78 | bool |
| 79 | help |
| 80 | --- a/net/core/dev.c |
| 81 | +++ b/net/core/dev.c |
| 82 | @@ -2243,9 +2243,19 @@ int dev_hard_start_xmit(struct sk_buff * |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | - skb_len = skb->len; |
| 87 | - rc = ops->ndo_start_xmit(skb, dev); |
| 88 | - trace_net_dev_xmit(skb, rc, dev, skb_len); |
| 89 | +#ifdef CONFIG_ETHERNET_PACKET_MANGLE |
| 90 | + if (!dev->eth_mangle_tx || |
| 91 | + (skb = dev->eth_mangle_tx(dev, skb)) != NULL) |
| 92 | +#else |
| 93 | + if (1) |
| 94 | +#endif |
| 95 | + { |
| 96 | + skb_len = skb->len; |
| 97 | + rc = ops->ndo_start_xmit(skb, dev); |
| 98 | + trace_net_dev_xmit(skb, rc, dev, skb_len); |
| 99 | + } else { |
| 100 | + rc = NETDEV_TX_OK; |
| 101 | + } |
| 102 | if (rc == NETDEV_TX_OK) |
| 103 | txq_trans_update(txq); |
| 104 | return rc; |
| 105 | @@ -2265,9 +2275,19 @@ gso: |
| 106 | if (dev->priv_flags & IFF_XMIT_DST_RELEASE) |
| 107 | skb_dst_drop(nskb); |
| 108 | |
| 109 | - skb_len = nskb->len; |
| 110 | - rc = ops->ndo_start_xmit(nskb, dev); |
| 111 | - trace_net_dev_xmit(nskb, rc, dev, skb_len); |
| 112 | +#ifdef CONFIG_ETHERNET_PACKET_MANGLE |
| 113 | + if (!dev->eth_mangle_tx || |
| 114 | + (nskb = dev->eth_mangle_tx(dev, nskb)) != NULL) |
| 115 | +#else |
| 116 | + if (1) |
| 117 | +#endif |
| 118 | + { |
| 119 | + skb_len = nskb->len; |
| 120 | + rc = ops->ndo_start_xmit(nskb, dev); |
| 121 | + trace_net_dev_xmit(nskb, rc, dev, skb_len); |
| 122 | + } else { |
| 123 | + rc = NETDEV_TX_OK; |
| 124 | + } |
| 125 | if (unlikely(rc != NETDEV_TX_OK)) { |
| 126 | if (rc & ~NETDEV_TX_MASK) |
| 127 | goto out_kfree_gso_skb; |
| 128 | --- a/net/core/skbuff.c |
| 129 | +++ b/net/core/skbuff.c |
| 130 | @@ -60,6 +60,7 @@ |
| 131 | #include <linux/scatterlist.h> |
| 132 | #include <linux/errqueue.h> |
| 133 | #include <linux/prefetch.h> |
| 134 | +#include <linux/if.h> |
| 135 | |
| 136 | #include <net/protocol.h> |
| 137 | #include <net/dst.h> |
| 138 | @@ -441,6 +442,22 @@ struct sk_buff *__netdev_alloc_skb(struc |
| 139 | } |
| 140 | EXPORT_SYMBOL(__netdev_alloc_skb); |
| 141 | |
| 142 | +struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, |
| 143 | + unsigned int length, gfp_t gfp) |
| 144 | +{ |
| 145 | + struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); |
| 146 | + |
| 147 | +#ifdef CONFIG_ETHERNET_PACKET_MANGLE |
| 148 | + if (dev->priv_flags & IFF_NO_IP_ALIGN) |
| 149 | + return skb; |
| 150 | +#endif |
| 151 | + |
| 152 | + if (NET_IP_ALIGN && skb) |
| 153 | + skb_reserve(skb, NET_IP_ALIGN); |
| 154 | + return skb; |
| 155 | +} |
| 156 | +EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); |
| 157 | + |
| 158 | void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, |
| 159 | int size, unsigned int truesize) |
| 160 | { |
| 161 | --- a/net/ethernet/eth.c |
| 162 | +++ b/net/ethernet/eth.c |
| 163 | @@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *sk |
| 164 | struct ethhdr *eth; |
| 165 | |
| 166 | skb->dev = dev; |
| 167 | + |
| 168 | +#ifdef CONFIG_ETHERNET_PACKET_MANGLE |
| 169 | + if (dev->eth_mangle_rx) |
| 170 | + dev->eth_mangle_rx(dev, skb); |
| 171 | +#endif |
| 172 | + |
| 173 | skb_reset_mac_header(skb); |
| 174 | skb_pull_inline(skb, ETH_HLEN); |
| 175 | eth = eth_hdr(skb); |
| 176 | |