]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/ipvs/ip_vs_proto_udp.c
net: ip_vs_proto_{tcp,udp} build fix
[linux-2.6-omap-h63xx.git] / net / ipv4 / ipvs / ip_vs_proto_udp.c
index fd8bd934cc02395c8ede83158e2501df87811222..6eb6039d63434f6ecc4bd511edb390e0e91bbd6a 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <net/ip_vs.h>
 #include <net/ip.h>
+#include <net/ip6_checksum.h>
 
 static struct ip_vs_conn *
 udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
@@ -141,12 +142,34 @@ udp_fast_csum_update(int af, struct udphdr *uhdr,
                uhdr->check = CSUM_MANGLED_0;
 }
 
+static inline void
+udp_partial_csum_update(int af, struct udphdr *uhdr,
+                    const union nf_inet_addr *oldip,
+                    const union nf_inet_addr *newip,
+                    __be16 oldlen, __be16 newlen)
+{
+#ifdef CONFIG_IP_VS_IPV6
+       if (af == AF_INET6)
+               uhdr->check =
+                       csum_fold(ip_vs_check_diff16(oldip->ip6, newip->ip6,
+                                        ip_vs_check_diff2(oldlen, newlen,
+                                               ~csum_unfold(uhdr->check))));
+       else
+#endif
+       uhdr->check =
+               csum_fold(ip_vs_check_diff4(oldip->ip, newip->ip,
+                               ip_vs_check_diff2(oldlen, newlen,
+                                               ~csum_unfold(uhdr->check))));
+}
+
+
 static int
 udp_snat_handler(struct sk_buff *skb,
                 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
        struct udphdr *udph;
        unsigned int udphoff;
+       int oldlen;
 
 #ifdef CONFIG_IP_VS_IPV6
        if (cp->af == AF_INET6)
@@ -154,6 +177,7 @@ udp_snat_handler(struct sk_buff *skb,
        else
 #endif
                udphoff = ip_hdrlen(skb);
+       oldlen = skb->len - udphoff;
 
        /* csum_check requires unshared skb */
        if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -177,7 +201,11 @@ udp_snat_handler(struct sk_buff *skb,
        /*
         *      Adjust UDP checksums
         */
-       if (!cp->app && (udph->check != 0)) {
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
+                                       htonl(oldlen),
+                                       htonl(skb->len - udphoff));
+       } else if (!cp->app && (udph->check != 0)) {
                /* Only port and addr are changed, do fast csum update */
                udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
                                     cp->dport, cp->vport);
@@ -216,6 +244,7 @@ udp_dnat_handler(struct sk_buff *skb,
 {
        struct udphdr *udph;
        unsigned int udphoff;
+       int oldlen;
 
 #ifdef CONFIG_IP_VS_IPV6
        if (cp->af == AF_INET6)
@@ -223,6 +252,7 @@ udp_dnat_handler(struct sk_buff *skb,
        else
 #endif
                udphoff = ip_hdrlen(skb);
+       oldlen = skb->len - udphoff;
 
        /* csum_check requires unshared skb */
        if (!skb_make_writable(skb, udphoff+sizeof(*udph)))
@@ -247,7 +277,11 @@ udp_dnat_handler(struct sk_buff *skb,
        /*
         *      Adjust UDP checksums
         */
-       if (!cp->app && (udph->check != 0)) {
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr,
+                                       htonl(oldlen),
+                                       htonl(skb->len - udphoff));
+       } else if (!cp->app && (udph->check != 0)) {
                /* Only port and addr are changed, do fast csum update */
                udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr,
                                     cp->vport, cp->dport);
@@ -408,12 +442,15 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
                                break;
                        spin_unlock(&udp_app_lock);
 
-                       IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
-                                 "%u.%u.%u.%u:%u to app %s on port %u\n",
-                                 __func__,
-                                 NIPQUAD(cp->caddr.ip), ntohs(cp->cport),
-                                 NIPQUAD(cp->vaddr.ip), ntohs(cp->vport),
-                                 inc->name, ntohs(inc->port));
+                       IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
+                                     "%s:%u to app %s on port %u\n",
+                                     __func__,
+                                     IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+                                     ntohs(cp->cport),
+                                     IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+                                     ntohs(cp->vport),
+                                     inc->name, ntohs(inc->port));
+
                        cp->app = inc;
                        if (inc->init_conn)
                                result = inc->init_conn(inc, cp);