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