aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/udp.c
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2009-07-09 04:09:47 -0400
committerDavid S. Miller <davem@davemloft.net>2009-07-12 17:29:21 -0400
commitd7ca4cc01fd154f2da30ae6dae160fa5800af758 (patch)
tree8e772bbb2320f4b109e20e9e588345bd1a51fb12 /net/ipv4/udp.c
parent30ffee8480c13fbcf8ab6c28e31f79dfff683117 (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.c61
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
1819int 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
1838struct 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);
1876out:
1877 return segs;
1878}
1879
1819EXPORT_SYMBOL(udp_disconnect); 1880EXPORT_SYMBOL(udp_disconnect);
1820EXPORT_SYMBOL(udp_ioctl); 1881EXPORT_SYMBOL(udp_ioctl);
1821EXPORT_SYMBOL(udp_prot); 1882EXPORT_SYMBOL(udp_prot);