diff options
-rw-r--r-- | include/net/inet6_connection_sock.h | 31 | ||||
-rw-r--r-- | include/net/request_sock.h | 2 | ||||
-rw-r--r-- | net/ipv6/Makefile | 3 | ||||
-rw-r--r-- | net/ipv6/inet6_connection_sock.c | 96 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 78 |
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 000000000000..aa30ebde70dc --- /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 | |||
18 | struct sock; | ||
19 | struct request_sock; | ||
20 | |||
21 | extern 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 | |||
28 | extern 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 b52cc52ffe39..11641c9384f7 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 | ||
245 | static inline void reqsk_queue_hash_req(struct request_sock_queue *queue, | 245 | static 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 6460eec834b7..9601fd7f9d66 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 | ||
13 | ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ | 14 | ipv6-$(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 000000000000..04ff44344f90 --- /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 | */ | ||
29 | static 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 | |||
48 | struct 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 | |||
80 | EXPORT_SYMBOL_GPL(inet6_csk_search_req); | ||
81 | |||
82 | void 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 | |||
96 | EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add); | ||
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index bf41f84d6692..5a10d30cec4a 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 | |||
125 | static 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 | |||
145 | static 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 | |||
175 | static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len, | 122 | static __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 | ||
1006 | static 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 | ||
1090 | drop: | 1026 | drop: |