aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inet6_connection_sock.h31
-rw-r--r--include/net/request_sock.h2
-rw-r--r--net/ipv6/Makefile3
-rw-r--r--net/ipv6/inet6_connection_sock.c96
-rw-r--r--net/ipv6/tcp_ipv6.c78
5 files changed, 137 insertions, 73 deletions
diff --git a/include/net/inet6_connection_sock.h b/include/net/inet6_connection_sock.h
new file mode 100644
index 00000000000..aa30ebde70d
--- /dev/null
+++ b/include/net/inet6_connection_sock.h
@@ -0,0 +1,31 @@
1/*
2 * NET Generic infrastructure for INET6 connection oriented protocols.
3 *
4 * Authors: Many people, see the TCPv6 sources
5 *
6 * From code originally in TCPv6
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#ifndef _INET6_CONNECTION_SOCK_H
14#define _INET6_CONNECTION_SOCK_H
15
16#include <linux/types.h>
17
18struct sock;
19struct request_sock;
20
21extern struct request_sock *inet6_csk_search_req(const struct sock *sk,
22 struct request_sock ***prevp,
23 const __u16 rport,
24 const struct in6_addr *raddr,
25 const struct in6_addr *laddr,
26 const int iif);
27
28extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
29 struct request_sock *req,
30 const unsigned long timeout);
31#endif /* _INET6_CONNECTION_SOCK_H */
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index b52cc52ffe3..11641c9384f 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -244,7 +244,7 @@ static inline int reqsk_queue_is_full(const struct request_sock_queue *queue)
244 244
245static inline void reqsk_queue_hash_req(struct request_sock_queue *queue, 245static inline void reqsk_queue_hash_req(struct request_sock_queue *queue,
246 u32 hash, struct request_sock *req, 246 u32 hash, struct request_sock *req,
247 unsigned timeout) 247 unsigned long timeout)
248{ 248{
249 struct listen_sock *lopt = queue->listen_opt; 249 struct listen_sock *lopt = queue->listen_opt;
250 250
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 6460eec834b..9601fd7f9d6 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -8,7 +8,8 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
8 route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \ 8 route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
9 protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ 9 protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
10 exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ 10 exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
11 ip6_flowlabel.o ipv6_syms.o netfilter.o 11 ip6_flowlabel.o ipv6_syms.o netfilter.o \
12 inet6_connection_sock.o
12 13
13ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ 14ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
14 xfrm6_output.o 15 xfrm6_output.o
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
new file mode 100644
index 00000000000..04ff44344f9
--- /dev/null
+++ b/net/ipv6/inet6_connection_sock.c
@@ -0,0 +1,96 @@
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * Support for INET6 connection oriented protocols.
7 *
8 * Authors: See the TCPv6 sources
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or(at your option) any later version.
14 */
15
16#include <linux/config.h>
17#include <linux/module.h>
18#include <linux/in6.h>
19#include <linux/ipv6.h>
20#include <linux/jhash.h>
21
22#include <net/addrconf.h>
23#include <net/inet_connection_sock.h>
24#include <net/sock.h>
25
26/*
27 * request_sock (formerly open request) hash tables.
28 */
29static u32 inet6_synq_hash(const struct in6_addr *raddr, const u16 rport,
30 const u32 rnd, const u16 synq_hsize)
31{
32 u32 a = raddr->s6_addr32[0];
33 u32 b = raddr->s6_addr32[1];
34 u32 c = raddr->s6_addr32[2];
35
36 a += JHASH_GOLDEN_RATIO;
37 b += JHASH_GOLDEN_RATIO;
38 c += rnd;
39 __jhash_mix(a, b, c);
40
41 a += raddr->s6_addr32[3];
42 b += (u32)rport;
43 __jhash_mix(a, b, c);
44
45 return c & (synq_hsize - 1);
46}
47
48struct request_sock *inet6_csk_search_req(const struct sock *sk,
49 struct request_sock ***prevp,
50 const __u16 rport,
51 const struct in6_addr *raddr,
52 const struct in6_addr *laddr,
53 const int iif)
54{
55 const struct inet_connection_sock *icsk = inet_csk(sk);
56 struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
57 struct request_sock *req, **prev;
58
59 for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport,
60 lopt->hash_rnd,
61 lopt->nr_table_entries)];
62 (req = *prev) != NULL;
63 prev = &req->dl_next) {
64 const struct tcp6_request_sock *treq = tcp6_rsk(req);
65
66 if (inet_rsk(req)->rmt_port == rport &&
67 req->rsk_ops->family == AF_INET6 &&
68 ipv6_addr_equal(&treq->rmt_addr, raddr) &&
69 ipv6_addr_equal(&treq->loc_addr, laddr) &&
70 (!treq->iif || treq->iif == iif)) {
71 BUG_TRAP(req->sk == NULL);
72 *prevp = prev;
73 return req;
74 }
75 }
76
77 return NULL;
78}
79
80EXPORT_SYMBOL_GPL(inet6_csk_search_req);
81
82void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
83 struct request_sock *req,
84 const unsigned long timeout)
85{
86 struct inet_connection_sock *icsk = inet_csk(sk);
87 struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
88 const u32 h = inet6_synq_hash(&tcp6_rsk(req)->rmt_addr,
89 inet_rsk(req)->rmt_port,
90 lopt->hash_rnd, lopt->nr_table_entries);
91
92 reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
93 inet_csk_reqsk_queue_added(sk, timeout);
94}
95
96EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index bf41f84d669..5a10d30cec4 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -48,6 +48,7 @@
48#include <net/tcp.h> 48#include <net/tcp.h>
49#include <net/ndisc.h> 49#include <net/ndisc.h>
50#include <net/inet6_hashtables.h> 50#include <net/inet6_hashtables.h>
51#include <net/inet6_connection_sock.h>
51#include <net/ipv6.h> 52#include <net/ipv6.h>
52#include <net/transp_v6.h> 53#include <net/transp_v6.h>
53#include <net/addrconf.h> 54#include <net/addrconf.h>
@@ -118,60 +119,6 @@ static void tcp_v6_hash(struct sock *sk)
118 } 119 }
119} 120}
120 121
121/*
122 * Open request hash tables.
123 */
124
125static u32 tcp_v6_synq_hash(const struct in6_addr *raddr, const u16 rport, const u32 rnd)
126{
127 u32 a, b, c;
128
129 a = raddr->s6_addr32[0];
130 b = raddr->s6_addr32[1];
131 c = raddr->s6_addr32[2];
132
133 a += JHASH_GOLDEN_RATIO;
134 b += JHASH_GOLDEN_RATIO;
135 c += rnd;
136 __jhash_mix(a, b, c);
137
138 a += raddr->s6_addr32[3];
139 b += (u32) rport;
140 __jhash_mix(a, b, c);
141
142 return c & (TCP_SYNQ_HSIZE - 1);
143}
144
145static struct request_sock *tcp_v6_search_req(const struct sock *sk,
146 struct request_sock ***prevp,
147 __u16 rport,
148 struct in6_addr *raddr,
149 struct in6_addr *laddr,
150 int iif)
151{
152 const struct inet_connection_sock *icsk = inet_csk(sk);
153 struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
154 struct request_sock *req, **prev;
155
156 for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport, lopt->hash_rnd)];
157 (req = *prev) != NULL;
158 prev = &req->dl_next) {
159 const struct tcp6_request_sock *treq = tcp6_rsk(req);
160
161 if (inet_rsk(req)->rmt_port == rport &&
162 req->rsk_ops->family == AF_INET6 &&
163 ipv6_addr_equal(&treq->rmt_addr, raddr) &&
164 ipv6_addr_equal(&treq->loc_addr, laddr) &&
165 (!treq->iif || treq->iif == iif)) {
166 BUG_TRAP(req->sk == NULL);
167 *prevp = prev;
168 return req;
169 }
170 }
171
172 return NULL;
173}
174
175static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len, 122static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
176 struct in6_addr *saddr, 123 struct in6_addr *saddr,
177 struct in6_addr *daddr, 124 struct in6_addr *daddr,
@@ -662,8 +609,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
662 if (sock_owned_by_user(sk)) 609 if (sock_owned_by_user(sk))
663 goto out; 610 goto out;
664 611
665 req = tcp_v6_search_req(sk, &prev, th->dest, &hdr->daddr, 612 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
666 &hdr->saddr, inet6_iif(skb)); 613 &hdr->saddr, inet6_iif(skb));
667 if (!req) 614 if (!req)
668 goto out; 615 goto out;
669 616
@@ -978,8 +925,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
978 struct sock *nsk; 925 struct sock *nsk;
979 926
980 /* Find possible connection requests. */ 927 /* Find possible connection requests. */
981 req = tcp_v6_search_req(sk, &prev, th->source, &skb->nh.ipv6h->saddr, 928 req = inet6_csk_search_req(sk, &prev, th->source,
982 &skb->nh.ipv6h->daddr, inet6_iif(skb)); 929 &skb->nh.ipv6h->saddr,
930 &skb->nh.ipv6h->daddr, inet6_iif(skb));
983 if (req) 931 if (req)
984 return tcp_check_req(sk, skb, req, prev); 932 return tcp_check_req(sk, skb, req, prev);
985 933
@@ -1003,17 +951,6 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1003 return sk; 951 return sk;
1004} 952}
1005 953
1006static void tcp_v6_synq_add(struct sock *sk, struct request_sock *req)
1007{
1008 struct inet_connection_sock *icsk = inet_csk(sk);
1009 struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
1010 const u32 h = tcp_v6_synq_hash(&tcp6_rsk(req)->rmt_addr, inet_rsk(req)->rmt_port, lopt->hash_rnd);
1011
1012 reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, TCP_TIMEOUT_INIT);
1013 inet_csk_reqsk_queue_added(sk, TCP_TIMEOUT_INIT);
1014}
1015
1016
1017/* FIXME: this is substantially similar to the ipv4 code. 954/* FIXME: this is substantially similar to the ipv4 code.
1018 * Can some kind of merge be done? -- erics 955 * Can some kind of merge be done? -- erics
1019 */ 956 */
@@ -1083,8 +1020,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1083 if (tcp_v6_send_synack(sk, req, NULL)) 1020 if (tcp_v6_send_synack(sk, req, NULL))
1084 goto drop; 1021 goto drop;
1085 1022
1086 tcp_v6_synq_add(sk, req); 1023 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1087
1088 return 0; 1024 return 0;
1089 1025
1090drop: 1026drop: