]> Pileus Git - ~andy/linux/blobdiff - net/ipv6/tcp_ipv6.c
ipv6: Separate tcp offload functionality
[~andy/linux] / net / ipv6 / tcp_ipv6.c
index 26175bffbaa060ad8da6357330ff596a5391cef6..5bed594b429d06fe0f920187dc70911824551daa 100644 (file)
 
 #include <linux/crypto.h>
 #include <linux/scatterlist.h>
+#include "ip6_offload.h"
 
 static void    tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
 static void    tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
                                      struct request_sock *req);
 
 static int     tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
-static void    __tcp_v6_send_check(struct sk_buff *skb,
-                                   const struct in6_addr *saddr,
-                                   const struct in6_addr *daddr);
 
 static const struct inet_connection_sock_af_ops ipv6_mapped;
 static const struct inet_connection_sock_af_ops ipv6_specific;
@@ -119,14 +117,6 @@ static void tcp_v6_hash(struct sock *sk)
        }
 }
 
-static __inline__ __sum16 tcp_v6_check(int len,
-                                  const struct in6_addr *saddr,
-                                  const struct in6_addr *daddr,
-                                  __wsum base)
-{
-       return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
-}
-
 static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
 {
        return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
@@ -495,9 +485,12 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
                             struct request_values *rvp)
 {
        struct flowi6 fl6;
+       int res;
 
-       TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
-       return tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0);
+       res = tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0);
+       if (!res)
+               TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+       return res;
 }
 
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
@@ -719,94 +712,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
 };
 #endif
 
-static void __tcp_v6_send_check(struct sk_buff *skb,
-                               const struct in6_addr *saddr, const struct in6_addr *daddr)
-{
-       struct tcphdr *th = tcp_hdr(skb);
-
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
-               skb->csum_start = skb_transport_header(skb) - skb->head;
-               skb->csum_offset = offsetof(struct tcphdr, check);
-       } else {
-               th->check = tcp_v6_check(skb->len, saddr, daddr,
-                                        csum_partial(th, th->doff << 2,
-                                                     skb->csum));
-       }
-}
-
-static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
-{
-       struct ipv6_pinfo *np = inet6_sk(sk);
-
-       __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
-}
-
-static int tcp_v6_gso_send_check(struct sk_buff *skb)
-{
-       const struct ipv6hdr *ipv6h;
-       struct tcphdr *th;
-
-       if (!pskb_may_pull(skb, sizeof(*th)))
-               return -EINVAL;
-
-       ipv6h = ipv6_hdr(skb);
-       th = tcp_hdr(skb);
-
-       th->check = 0;
-       skb->ip_summed = CHECKSUM_PARTIAL;
-       __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
-       return 0;
-}
-
-static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
-                                        struct sk_buff *skb)
-{
-       const struct ipv6hdr *iph = skb_gro_network_header(skb);
-       __wsum wsum;
-       __sum16 sum;
-
-       switch (skb->ip_summed) {
-       case CHECKSUM_COMPLETE:
-               if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
-                                 skb->csum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       break;
-               }
-flush:
-               NAPI_GRO_CB(skb)->flush = 1;
-               return NULL;
-
-       case CHECKSUM_NONE:
-               wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
-                                                   skb_gro_len(skb),
-                                                   IPPROTO_TCP, 0));
-               sum = csum_fold(skb_checksum(skb,
-                                            skb_gro_offset(skb),
-                                            skb_gro_len(skb),
-                                            wsum));
-               if (sum)
-                       goto flush;
-
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-               break;
-       }
-
-       return tcp_gro_receive(head, skb);
-}
-
-static int tcp6_gro_complete(struct sk_buff *skb)
-{
-       const struct ipv6hdr *iph = ipv6_hdr(skb);
-       struct tcphdr *th = tcp_hdr(skb);
-
-       th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
-                                 &iph->saddr, &iph->daddr, 0);
-       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
-
-       return tcp_gro_complete(skb);
-}
-
 static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
                                 u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass)
 {
@@ -1364,7 +1269,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        tcp_initialize_rcv_mss(newsk);
        tcp_synack_rtt_meas(newsk, req);
-       newtp->total_retrans = req->retrans;
+       newtp->total_retrans = req->num_retrans;
 
        newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
        newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
@@ -1741,11 +1646,11 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
                skb->destructor = sock_edemux;
                if (sk->sk_state != TCP_TIME_WAIT) {
                        struct dst_entry *dst = sk->sk_rx_dst;
-                       struct inet_sock *icsk = inet_sk(sk);
+
                        if (dst)
                                dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
                        if (dst &&
-                           icsk->rx_dst_ifindex == skb->skb_iif)
+                           inet_sk(sk)->rx_dst_ifindex == skb->skb_iif)
                                skb_dst_set_noref(skb, dst);
                }
        }
@@ -1866,7 +1771,7 @@ static void get_openreq6(struct seq_file *seq,
                   0,0, /* could print option size, but that is af dependent. */
                   1,   /* timers active (only the expire timer) */
                   jiffies_to_clock_t(ttd),
-                  req->retrans,
+                  req->num_timeout,
                   from_kuid_munged(seq_user_ns(seq), uid),
                   0,  /* non standard timer */
                   0, /* open_requests have no inode */
@@ -2063,10 +1968,6 @@ static const struct inet6_protocol tcpv6_protocol = {
        .early_demux    =       tcp_v6_early_demux,
        .handler        =       tcp_v6_rcv,
        .err_handler    =       tcp_v6_err,
-       .gso_send_check =       tcp_v6_gso_send_check,
-       .gso_segment    =       tcp_tso_segment,
-       .gro_receive    =       tcp6_gro_receive,
-       .gro_complete   =       tcp6_gro_complete,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
@@ -2106,10 +2007,14 @@ int __init tcpv6_init(void)
 {
        int ret;
 
-       ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
+       ret = tcpv6_offload_init();
        if (ret)
                goto out;
 
+       ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
+       if (ret)
+               goto out_offload;
+
        /* register inet6 protocol */
        ret = inet6_register_protosw(&tcpv6_protosw);
        if (ret)
@@ -2121,10 +2026,12 @@ int __init tcpv6_init(void)
 out:
        return ret;
 
-out_tcpv6_protocol:
-       inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
 out_tcpv6_protosw:
        inet6_unregister_protosw(&tcpv6_protosw);
+out_tcpv6_protocol:
+       inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
+out_offload:
+       tcpv6_offload_cleanup();
        goto out;
 }
 
@@ -2133,4 +2040,5 @@ void tcpv6_exit(void)
        unregister_pernet_subsys(&tcpv6_net_ops);
        inet6_unregister_protosw(&tcpv6_protosw);
        inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
+       tcpv6_offload_cleanup();
 }