| 1 | --- a/include/linux/skbuff.h |
| 2 | +++ b/include/linux/skbuff.h |
| 3 | @@ -912,6 +912,49 @@ static inline void skb_reserve(struct sk |
| 4 | skb->tail+=len; |
| 5 | } |
| 6 | |
| 7 | +/* |
| 8 | + * CPUs often take a performance hit when accessing unaligned memory |
| 9 | + * locations. The actual performance hit varies, it can be small if the |
| 10 | + * hardware handles it or large if we have to take an exception and fix it |
| 11 | + * in software. |
| 12 | + * |
| 13 | + * Since an ethernet header is 14 bytes network drivers often end up with |
| 14 | + * the IP header at an unaligned offset. The IP header can be aligned by |
| 15 | + * shifting the start of the packet by 2 bytes. Drivers should do this |
| 16 | + * with: |
| 17 | + * |
| 18 | + * skb_reserve(NET_IP_ALIGN); |
| 19 | + * |
| 20 | + * The downside to this alignment of the IP header is that the DMA is now |
| 21 | + * unaligned. On some architectures the cost of an unaligned DMA is high |
| 22 | + * and this cost outweighs the gains made by aligning the IP header. |
| 23 | + * |
| 24 | + * Since this trade off varies between architectures, we allow NET_IP_ALIGN |
| 25 | + * to be overridden. |
| 26 | + */ |
| 27 | +#ifndef NET_IP_ALIGN |
| 28 | +#define NET_IP_ALIGN 2 |
| 29 | +#endif |
| 30 | + |
| 31 | +/* |
| 32 | + * The networking layer reserves some headroom in skb data (via |
| 33 | + * dev_alloc_skb). This is used to avoid having to reallocate skb data when |
| 34 | + * the header has to grow. In the default case, if the header has to grow |
| 35 | + * 16 bytes or less we avoid the reallocation. |
| 36 | + * |
| 37 | + * Unfortunately this headroom changes the DMA alignment of the resulting |
| 38 | + * network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive |
| 39 | + * on some architectures. An architecture can override this value, |
| 40 | + * perhaps setting it to a cacheline in size (since that will maintain |
| 41 | + * cacheline alignment of the DMA). It must be a power of 2. |
| 42 | + * |
| 43 | + * Various parts of the networking layer expect at least 16 bytes of |
| 44 | + * headroom, you should not reduce this. |
| 45 | + */ |
| 46 | +#ifndef NET_SKB_PAD |
| 47 | +#define NET_SKB_PAD 16 |
| 48 | +#endif |
| 49 | + |
| 50 | extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc); |
| 51 | |
| 52 | static inline void __skb_trim(struct sk_buff *skb, unsigned int len) |
| 53 | --- a/drivers/net/tun.c |
| 54 | +++ b/drivers/net/tun.c |
| 55 | @@ -185,22 +185,31 @@ static __inline__ ssize_t tun_get_user(s |
| 56 | { |
| 57 | struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) }; |
| 58 | struct sk_buff *skb; |
| 59 | - size_t len = count; |
| 60 | + size_t len = count, align = 0; |
| 61 | |
| 62 | if (!(tun->flags & TUN_NO_PI)) { |
| 63 | if ((len -= sizeof(pi)) > count) |
| 64 | return -EINVAL; |
| 65 | |
| 66 | - memcpy_fromiovec((void *)&pi, iv, sizeof(pi)); |
| 67 | + if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi))) |
| 68 | + return -EFAULT; |
| 69 | } |
| 70 | - |
| 71 | - if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { |
| 72 | + |
| 73 | + if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) |
| 74 | + align = NET_IP_ALIGN; |
| 75 | + |
| 76 | + if (!(skb = alloc_skb(len + align, GFP_KERNEL))) { |
| 77 | tun->stats.rx_dropped++; |
| 78 | return -ENOMEM; |
| 79 | } |
| 80 | |
| 81 | - skb_reserve(skb, 2); |
| 82 | - memcpy_fromiovec(skb_put(skb, len), iv, len); |
| 83 | + if (align) |
| 84 | + skb_reserve(skb, align); |
| 85 | + if (memcpy_fromiovec(skb_put(skb, len), iv, len)) { |
| 86 | + tun->stats.rx_dropped++; |
| 87 | + kfree_skb(skb); |
| 88 | + return -EFAULT; |
| 89 | + } |
| 90 | |
| 91 | skb->dev = &tun->dev; |
| 92 | switch (tun->flags & TUN_TYPE_MASK) { |
| 93 | @@ -271,7 +280,8 @@ static __inline__ ssize_t tun_put_user(s |
| 94 | pi.flags |= TUN_PKT_STRIP; |
| 95 | } |
| 96 | |
| 97 | - memcpy_toiovec(iv, (void *) &pi, sizeof(pi)); |
| 98 | + if(memcpy_toiovec(iv, (void *) &pi, sizeof(pi))) |
| 99 | + return -EFAULT; |
| 100 | total += sizeof(pi); |
| 101 | } |
| 102 | |
| 103 | |