generic-2.4: refresh patches
[openwrt/staging/yousong.git] / target / linux / generic-2.4 / patches / 230-tun_get_user_backport.patch
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