fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / ipv4 / ipvs / ip_vs_proto_udp.c
index 740d8d9..03f0a41 100644 (file)
  *
  */
 
+#include <linux/in.h>
+#include <linux/ip.h>
 #include <linux/kernel.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/udp.h>
 
 #include <net/ip_vs.h>
 
@@ -26,19 +29,20 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
                const struct iphdr *iph, unsigned int proto_off, int inverse)
 {
        struct ip_vs_conn *cp;
-       __u16 ports[2];
+       __be16 _ports[2], *pptr;
 
-       if (skb_copy_bits(skb, proto_off, ports, sizeof(ports)) < 0)
+       pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+       if (pptr == NULL)
                return NULL;
 
        if (likely(!inverse)) {
                cp = ip_vs_conn_in_get(iph->protocol,
-                                      iph->saddr, ports[0],
-                                      iph->daddr, ports[1]);
+                                      iph->saddr, pptr[0],
+                                      iph->daddr, pptr[1]);
        } else {
                cp = ip_vs_conn_in_get(iph->protocol,
-                                      iph->daddr, ports[1],
-                                      iph->saddr, ports[0]);
+                                      iph->daddr, pptr[1],
+                                      iph->saddr, pptr[0]);
        }
 
        return cp;
@@ -50,19 +54,21 @@ udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
                 const struct iphdr *iph, unsigned int proto_off, int inverse)
 {
        struct ip_vs_conn *cp;
-       __u16 ports[2];
+       __be16 _ports[2], *pptr;
 
-       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0)
+       pptr = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+                                 sizeof(_ports), _ports);
+       if (pptr == NULL)
                return NULL;
 
        if (likely(!inverse)) {
                cp = ip_vs_conn_out_get(iph->protocol,
-                                       iph->saddr, ports[0],
-                                       iph->daddr, ports[1]);
+                                       iph->saddr, pptr[0],
+                                       iph->daddr, pptr[1]);
        } else {
                cp = ip_vs_conn_out_get(iph->protocol,
-                                       iph->daddr, ports[1],
-                                       iph->saddr, ports[0]);
+                                       iph->daddr, pptr[1],
+                                       iph->saddr, pptr[0]);
        }
 
        return cp;
@@ -74,15 +80,17 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
                  int *verdict, struct ip_vs_conn **cpp)
 {
        struct ip_vs_service *svc;
-       struct udphdr udph;
+       struct udphdr _udph, *uh;
 
-       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0) {
+       uh = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+                               sizeof(_udph), &_udph);
+       if (uh == NULL) {
                *verdict = NF_DROP;
                return 0;
        }
 
-       if ((svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol,
-                                    skb->nh.iph->daddr, udph.dest))) {
+       if ((svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol,
+                                    skb->nh.iph->daddr, uh->dest))) {
                if (ip_vs_todrop()) {
                        /*
                         * It seems that we are very loaded.
@@ -109,15 +117,15 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static inline void
-udp_fast_csum_update(struct udphdr *uhdr, u32 oldip, u32 newip,
-                    u16 oldport, u16 newport)
+udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
+                    __be16 oldport, __be16 newport)
 {
        uhdr->check =
-               ip_vs_check_diff(~oldip, newip,
-                                ip_vs_check_diff(oldport ^ 0xFFFF,
-                                                 newport, uhdr->check));
+               csum_fold(ip_vs_check_diff4(oldip, newip,
+                                ip_vs_check_diff2(oldport, newport,
+                                       ~csum_unfold(uhdr->check))));
        if (!uhdr->check)
-               uhdr->check = 0xFFFF;
+               uhdr->check = CSUM_MANGLED_0;
 }
 
 static int
@@ -153,7 +161,7 @@ udp_snat_handler(struct sk_buff **pskb,
                /* Only port and addr are changed, do fast csum update */
                udp_fast_csum_update(udph, cp->daddr, cp->vaddr,
                                     cp->dport, cp->vport);
-               if ((*pskb)->ip_summed == CHECKSUM_HW)
+               if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
                        (*pskb)->ip_summed = CHECKSUM_NONE;
        } else {
                /* full checksum calculation */
@@ -165,8 +173,8 @@ udp_snat_handler(struct sk_buff **pskb,
                                                cp->protocol,
                                                (*pskb)->csum);
                if (udph->check == 0)
-                       udph->check = 0xFFFF;
-               IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%d)\n",
+                       udph->check = CSUM_MANGLED_0;
+               IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
                          pp->name, udph->check,
                          (char*)&(udph->check) - (char*)udph);
        }
@@ -208,7 +216,7 @@ udp_dnat_handler(struct sk_buff **pskb,
                /* Only port and addr are changed, do fast csum update */
                udp_fast_csum_update(udph, cp->vaddr, cp->daddr,
                                     cp->vport, cp->dport);
-               if ((*pskb)->ip_summed == CHECKSUM_HW)
+               if ((*pskb)->ip_summed == CHECKSUM_COMPLETE)
                        (*pskb)->ip_summed = CHECKSUM_NONE;
        } else {
                /* full checksum calculation */
@@ -220,7 +228,7 @@ udp_dnat_handler(struct sk_buff **pskb,
                                                cp->protocol,
                                                (*pskb)->csum);
                if (udph->check == 0)
-                       udph->check = 0xFFFF;
+                       udph->check = CSUM_MANGLED_0;
                (*pskb)->ip_summed = CHECKSUM_UNNECESSARY;
        }
        return 1;
@@ -230,18 +238,19 @@ udp_dnat_handler(struct sk_buff **pskb,
 static int
 udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
 {
-       struct udphdr udph;
+       struct udphdr _udph, *uh;
        unsigned int udphoff = skb->nh.iph->ihl*4;
 
-       if (skb_copy_bits(skb, udphoff, &udph, sizeof(udph)) < 0)
+       uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
+       if (uh == NULL)
                return 0;
 
-       if (udph.check != 0) {
+       if (uh->check != 0) {
                switch (skb->ip_summed) {
                case CHECKSUM_NONE:
                        skb->csum = skb_checksum(skb, udphoff,
                                                 skb->len - udphoff, 0);
-               case CHECKSUM_HW:
+               case CHECKSUM_COMPLETE:
                        if (csum_tcpudp_magic(skb->nh.iph->saddr,
                                              skb->nh.iph->daddr,
                                              skb->len - udphoff,
@@ -253,7 +262,7 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
                        }
                        break;
                default:
-                       /* CHECKSUM_UNNECESSARY */
+                       /* No need to checksum. */
                        break;
                }
        }
@@ -271,18 +280,20 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
 #define        UDP_APP_TAB_MASK        (UDP_APP_TAB_SIZE - 1)
 
 static struct list_head udp_apps[UDP_APP_TAB_SIZE];
-static spinlock_t udp_app_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(udp_app_lock);
 
-static inline __u16 udp_app_hashkey(__u16 port)
+static inline __u16 udp_app_hashkey(__be16 port)
 {
-       return ((port >> UDP_APP_TAB_BITS) ^ port) & UDP_APP_TAB_MASK;
+       return (((__force u16)port >> UDP_APP_TAB_BITS) ^ (__force u16)port)
+               & UDP_APP_TAB_MASK;
 }
 
 
 static int udp_register_app(struct ip_vs_app *inc)
 {
        struct ip_vs_app *i;
-       __u16 hash, port = inc->port;
+       __u16 hash;
+       __be16 port = inc->port;
        int ret = 0;
 
        hash = udp_app_hashkey(port);