diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2009-07-09 04:09:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-07-12 17:29:21 -0400 |
commit | d7ca4cc01fd154f2da30ae6dae160fa5800af758 (patch) | |
tree | 8e772bbb2320f4b109e20e9e588345bd1a51fb12 /net/ipv4/udp.c | |
parent | 30ffee8480c13fbcf8ab6c28e31f79dfff683117 (diff) |
udpv4: Handle large incoming UDP/IPv4 packets and support software UFO.
- validate and forward GSO UDP/IPv4 packets from untrusted sources.
- do software UFO if the outgoing device doesn't support UFO.
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 80e3812837ad..7bc2d082a49e 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1816,6 +1816,67 @@ void __init udp_init(void) | |||
1816 | sysctl_udp_wmem_min = SK_MEM_QUANTUM; | 1816 | sysctl_udp_wmem_min = SK_MEM_QUANTUM; |
1817 | } | 1817 | } |
1818 | 1818 | ||
1819 | int udp4_ufo_send_check(struct sk_buff *skb) | ||
1820 | { | ||
1821 | const struct iphdr *iph; | ||
1822 | struct udphdr *uh; | ||
1823 | |||
1824 | if (!pskb_may_pull(skb, sizeof(*uh))) | ||
1825 | return -EINVAL; | ||
1826 | |||
1827 | iph = ip_hdr(skb); | ||
1828 | uh = udp_hdr(skb); | ||
1829 | |||
1830 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, | ||
1831 | IPPROTO_UDP, 0); | ||
1832 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
1833 | skb->csum_offset = offsetof(struct udphdr, check); | ||
1834 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
1835 | return 0; | ||
1836 | } | ||
1837 | |||
1838 | struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features) | ||
1839 | { | ||
1840 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
1841 | unsigned int mss; | ||
1842 | int offset; | ||
1843 | __wsum csum; | ||
1844 | |||
1845 | mss = skb_shinfo(skb)->gso_size; | ||
1846 | if (unlikely(skb->len <= mss)) | ||
1847 | goto out; | ||
1848 | |||
1849 | if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { | ||
1850 | /* Packet is from an untrusted source, reset gso_segs. */ | ||
1851 | int type = skb_shinfo(skb)->gso_type; | ||
1852 | |||
1853 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) || | ||
1854 | !(type & (SKB_GSO_UDP)))) | ||
1855 | goto out; | ||
1856 | |||
1857 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); | ||
1858 | |||
1859 | segs = NULL; | ||
1860 | goto out; | ||
1861 | } | ||
1862 | |||
1863 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot | ||
1864 | * do checksum of UDP packets sent as multiple IP fragments. | ||
1865 | */ | ||
1866 | offset = skb->csum_start - skb_headroom(skb); | ||
1867 | csum = skb_checksum(skb, offset, skb->len- offset, 0); | ||
1868 | offset += skb->csum_offset; | ||
1869 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | ||
1870 | skb->ip_summed = CHECKSUM_NONE; | ||
1871 | |||
1872 | /* Fragment the skb. IP headers of the fragments are updated in | ||
1873 | * inet_gso_segment() | ||
1874 | */ | ||
1875 | segs = skb_segment(skb, features); | ||
1876 | out: | ||
1877 | return segs; | ||
1878 | } | ||
1879 | |||
1819 | EXPORT_SYMBOL(udp_disconnect); | 1880 | EXPORT_SYMBOL(udp_disconnect); |
1820 | EXPORT_SYMBOL(udp_ioctl); | 1881 | EXPORT_SYMBOL(udp_ioctl); |
1821 | EXPORT_SYMBOL(udp_prot); | 1882 | EXPORT_SYMBOL(udp_prot); |