blob: 075f540ec1975cdce6148e75661219cfe5decb6e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * TCP over IPv6
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003 * Linux INET6 implementation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09008 * Based on:
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * linux/net/ipv4/tcp.c
10 * linux/net/ipv4/tcp_input.c
11 * linux/net/ipv4/tcp_output.c
12 *
13 * Fixes:
14 * Hideaki YOSHIFUJI : sin6_scope_id support
15 * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
16 * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
17 * a single port at the same time.
18 * YOSHIFUJI Hideaki @USAGI: convert /proc/net/tcp6 to seq_file.
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version
23 * 2 of the License, or (at your option) any later version.
24 */
25
Herbert Xueb4dea52008-12-29 23:04:08 -080026#include <linux/bottom_half.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/errno.h>
29#include <linux/types.h>
30#include <linux/socket.h>
31#include <linux/sockios.h>
32#include <linux/net.h>
33#include <linux/jiffies.h>
34#include <linux/in.h>
35#include <linux/in6.h>
36#include <linux/netdevice.h>
37#include <linux/init.h>
38#include <linux/jhash.h>
39#include <linux/ipsec.h>
40#include <linux/times.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090041#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <linux/ipv6.h>
44#include <linux/icmpv6.h>
45#include <linux/random.h>
46
47#include <net/tcp.h>
48#include <net/ndisc.h>
Arnaldo Carvalho de Melo5324a042005-08-12 09:26:18 -030049#include <net/inet6_hashtables.h>
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -080050#include <net/inet6_connection_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <net/ipv6.h>
52#include <net/transp_v6.h>
53#include <net/addrconf.h>
54#include <net/ip6_route.h>
55#include <net/ip6_checksum.h>
56#include <net/inet_ecn.h>
57#include <net/protocol.h>
58#include <net/xfrm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <net/snmp.h>
60#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080061#include <net/timewait_sock.h>
Jeff Garzik18134be2007-10-26 22:53:14 -070062#include <net/netdma.h>
Denis V. Lunev3d58b5f2008-04-03 14:22:32 -070063#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include <asm/uaccess.h>
66
67#include <linux/proc_fs.h>
68#include <linux/seq_file.h>
69
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080070#include <linux/crypto.h>
71#include <linux/scatterlist.h>
72
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080073static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
Gui Jianfeng6edafaa2008-08-06 23:50:04 -070074static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
75 struct request_sock *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Stephen Hemminger3b401a82009-09-01 19:25:04 +000079static const struct inet_connection_sock_af_ops ipv6_mapped;
80static const struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080081#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +000082static const struct tcp_sock_af_ops tcp_sock_ipv6_specific;
83static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090084#else
85static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
86 struct in6_addr *addr)
87{
88 return NULL;
89}
David S. Millera9286302006-11-14 19:53:22 -080090#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static void tcp_v6_hash(struct sock *sk)
93{
94 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080095 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 tcp_prot.hash(sk);
97 return;
98 }
99 local_bh_disable();
Eric Dumazet9327f702009-12-04 03:46:54 +0000100 __inet6_hash(sk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 local_bh_enable();
102 }
103}
104
Herbert Xu684f2172009-01-08 10:41:23 -0800105static __inline__ __sum16 tcp_v6_check(int len,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900106 struct in6_addr *saddr,
107 struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800108 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
111}
112
Gerrit Renkera94f7232006-11-10 14:06:49 -0800113static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700115 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
116 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700117 tcp_hdr(skb)->dest,
118 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119}
120
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900121static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 int addr_len)
123{
124 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900125 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800126 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 struct ipv6_pinfo *np = inet6_sk(sk);
128 struct tcp_sock *tp = tcp_sk(sk);
129 struct in6_addr *saddr = NULL, *final_p = NULL, final;
130 struct flowi fl;
131 struct dst_entry *dst;
132 int addr_type;
133 int err;
134
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900135 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 return -EINVAL;
137
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900138 if (usin->sin6_family != AF_INET6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 return(-EAFNOSUPPORT);
140
141 memset(&fl, 0, sizeof(fl));
142
143 if (np->sndflow) {
144 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
145 IP6_ECN_flow_init(fl.fl6_flowlabel);
146 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
147 struct ip6_flowlabel *flowlabel;
148 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
149 if (flowlabel == NULL)
150 return -EINVAL;
151 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
152 fl6_sock_release(flowlabel);
153 }
154 }
155
156 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900157 * connect() to INADDR_ANY means loopback (BSD'ism).
158 */
159
160 if(ipv6_addr_any(&usin->sin6_addr))
161 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163 addr_type = ipv6_addr_type(&usin->sin6_addr);
164
165 if(addr_type & IPV6_ADDR_MULTICAST)
166 return -ENETUNREACH;
167
168 if (addr_type&IPV6_ADDR_LINKLOCAL) {
169 if (addr_len >= sizeof(struct sockaddr_in6) &&
170 usin->sin6_scope_id) {
171 /* If interface is set while binding, indices
172 * must coincide.
173 */
174 if (sk->sk_bound_dev_if &&
175 sk->sk_bound_dev_if != usin->sin6_scope_id)
176 return -EINVAL;
177
178 sk->sk_bound_dev_if = usin->sin6_scope_id;
179 }
180
181 /* Connect to link-local address requires an interface */
182 if (!sk->sk_bound_dev_if)
183 return -EINVAL;
184 }
185
186 if (tp->rx_opt.ts_recent_stamp &&
187 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
188 tp->rx_opt.ts_recent = 0;
189 tp->rx_opt.ts_recent_stamp = 0;
190 tp->write_seq = 0;
191 }
192
193 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
194 np->flow_label = fl.fl6_flowlabel;
195
196 /*
197 * TCP over IPv4
198 */
199
200 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800201 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 struct sockaddr_in sin;
203
204 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
205
206 if (__ipv6_only_sock(sk))
207 return -ENETUNREACH;
208
209 sin.sin_family = AF_INET;
210 sin.sin_port = usin->sin6_port;
211 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
212
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800213 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800215#ifdef CONFIG_TCP_MD5SIG
216 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
217#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
220
221 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800222 icsk->icsk_ext_hdr_len = exthdrlen;
223 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800225#ifdef CONFIG_TCP_MD5SIG
226 tp->af_specific = &tcp_sock_ipv6_specific;
227#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 goto failure;
229 } else {
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000230 ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
231 ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
232 &np->rcv_saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 }
234
235 return err;
236 }
237
238 if (!ipv6_addr_any(&np->rcv_saddr))
239 saddr = &np->rcv_saddr;
240
241 fl.proto = IPPROTO_TCP;
242 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
243 ipv6_addr_copy(&fl.fl6_src,
244 (saddr ? saddr : &np->saddr));
245 fl.oif = sk->sk_bound_dev_if;
Brian Haley51953d52009-10-05 08:24:16 +0000246 fl.mark = sk->sk_mark;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 fl.fl_ip_dport = usin->sin6_port;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000248 fl.fl_ip_sport = inet->inet_sport;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 if (np->opt && np->opt->srcrt) {
251 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
252 ipv6_addr_copy(&final, &fl.fl6_dst);
253 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
254 final_p = &final;
255 }
256
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700257 security_sk_classify_flow(sk, &fl);
258
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 err = ip6_dst_lookup(sk, &dst, &fl);
260 if (err)
261 goto failure;
262 if (final_p)
263 ipv6_addr_copy(&fl.fl6_dst, final_p);
264
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800265 err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
266 if (err < 0) {
David S. Miller14e50e52007-05-24 18:17:54 -0700267 if (err == -EREMOTE)
268 err = ip6_dst_blackhole(sk, &dst, &fl);
269 if (err < 0)
270 goto failure;
271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 if (saddr == NULL) {
274 saddr = &fl.fl6_src;
275 ipv6_addr_copy(&np->rcv_saddr, saddr);
276 }
277
278 /* set the source address */
279 ipv6_addr_copy(&np->saddr, saddr);
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000280 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700282 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700283 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800285 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800287 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
288 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
291
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000292 inet->inet_dport = usin->sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800295 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if (err)
297 goto late_failure;
298
299 if (!tp->write_seq)
300 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
301 np->daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000302 inet->inet_sport,
303 inet->inet_dport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 err = tcp_connect(sk);
306 if (err)
307 goto late_failure;
308
309 return 0;
310
311late_failure:
312 tcp_set_state(sk, TCP_CLOSE);
313 __sk_dst_reset(sk);
314failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000315 inet->inet_dport = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 sk->sk_route_caps = 0;
317 return err;
318}
319
320static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700321 u8 type, u8 code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
323 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300324 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 struct ipv6_pinfo *np;
326 struct sock *sk;
327 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900328 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 __u32 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700330 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700332 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800333 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
335 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700336 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
337 ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 return;
339 }
340
341 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700342 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return;
344 }
345
346 bh_lock_sock(sk);
347 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700348 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 if (sk->sk_state == TCP_CLOSE)
351 goto out;
352
353 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900354 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 if (sk->sk_state != TCP_LISTEN &&
356 !between(seq, tp->snd_una, tp->snd_nxt)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700357 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 goto out;
359 }
360
361 np = inet6_sk(sk);
362
363 if (type == ICMPV6_PKT_TOOBIG) {
364 struct dst_entry *dst = NULL;
365
366 if (sock_owned_by_user(sk))
367 goto out;
368 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
369 goto out;
370
371 /* icmp should have updated the destination cache entry */
372 dst = __sk_dst_check(sk, np->dst_cookie);
373
374 if (dst == NULL) {
375 struct inet_sock *inet = inet_sk(sk);
376 struct flowi fl;
377
378 /* BUGGG_FUTURE: Again, it is not clear how
379 to handle rthdr case. Ignore this complexity
380 for now.
381 */
382 memset(&fl, 0, sizeof(fl));
383 fl.proto = IPPROTO_TCP;
384 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
385 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
386 fl.oif = sk->sk_bound_dev_if;
Brian Haley51953d52009-10-05 08:24:16 +0000387 fl.mark = sk->sk_mark;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000388 fl.fl_ip_dport = inet->inet_dport;
389 fl.fl_ip_sport = inet->inet_sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700390 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
393 sk->sk_err_soft = -err;
394 goto out;
395 }
396
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800397 if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 sk->sk_err_soft = -err;
399 goto out;
400 }
401
402 } else
403 dst_hold(dst);
404
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800405 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 tcp_sync_mss(sk, dst_mtu(dst));
407 tcp_simple_retransmit(sk);
408 } /* else let the usual retransmit timer handle it */
409 dst_release(dst);
410 goto out;
411 }
412
413 icmpv6_err_convert(type, code, &err);
414
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700415 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700417 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 case TCP_LISTEN:
419 if (sock_owned_by_user(sk))
420 goto out;
421
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800422 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
423 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 if (!req)
425 goto out;
426
427 /* ICMPs are not backlogged, hence we cannot get
428 * an established socket here.
429 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700430 WARN_ON(req->sk != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700432 if (seq != tcp_rsk(req)->snt_isn) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700433 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 goto out;
435 }
436
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700437 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 goto out;
439
440 case TCP_SYN_SENT:
441 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900442 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 sk->sk_err = err;
445 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
446
447 tcp_done(sk);
448 } else
449 sk->sk_err_soft = err;
450 goto out;
451 }
452
453 if (!sock_owned_by_user(sk) && np->recverr) {
454 sk->sk_err = err;
455 sk->sk_error_report(sk);
456 } else
457 sk->sk_err_soft = err;
458
459out:
460 bh_unlock_sock(sk);
461 sock_put(sk);
462}
463
464
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000465static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
466 struct request_values *rvp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800468 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 struct ipv6_pinfo *np = inet6_sk(sk);
470 struct sk_buff * skb;
471 struct ipv6_txoptions *opt = NULL;
472 struct in6_addr * final_p = NULL, final;
473 struct flowi fl;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800474 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 int err = -1;
476
477 memset(&fl, 0, sizeof(fl));
478 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700479 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
480 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700482 fl.oif = treq->iif;
Brian Haley51953d52009-10-05 08:24:16 +0000483 fl.mark = sk->sk_mark;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700484 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
KOVACS Krisztianfd507032008-10-19 23:35:58 -0700485 fl.fl_ip_sport = inet_rsk(req)->loc_port;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700486 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800488 opt = np->opt;
489 if (opt && opt->srcrt) {
490 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
491 ipv6_addr_copy(&final, &fl.fl6_dst);
492 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
493 final_p = &final;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 }
495
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800496 err = ip6_dst_lookup(sk, &dst, &fl);
497 if (err)
498 goto done;
499 if (final_p)
500 ipv6_addr_copy(&fl.fl6_dst, final_p);
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800501 if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800502 goto done;
503
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000504 skb = tcp_make_synack(sk, dst, req, rvp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 if (skb) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700506 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Herbert Xu684f2172009-01-08 10:41:23 -0800508 th->check = tcp_v6_check(skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700509 &treq->loc_addr, &treq->rmt_addr,
Joe Perches07f07572008-11-19 15:44:53 -0800510 csum_partial(th, skb->len, skb->csum));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700512 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 err = ip6_xmit(sk, skb, &fl, opt, 0);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200514 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
516
517done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900518 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800520 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 return err;
522}
523
Octavian Purdila72659ec2010-01-17 19:09:39 -0800524static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
525 struct request_values *rvp)
526{
527 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
528 return tcp_v6_send_synack(sk, req, rvp);
529}
530
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800531static inline void syn_flood_warning(struct sk_buff *skb)
532{
533#ifdef CONFIG_SYN_COOKIES
534 if (sysctl_tcp_syncookies)
535 printk(KERN_INFO
536 "TCPv6: Possible SYN flooding on port %d. "
537 "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
538 else
539#endif
540 printk(KERN_INFO
541 "TCPv6: Possible SYN flooding on port %d. "
542 "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
543}
544
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700545static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
Wei Yongjun800d55f2009-02-23 21:45:33 +0000547 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548}
549
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800550#ifdef CONFIG_TCP_MD5SIG
551static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
552 struct in6_addr *addr)
553{
554 struct tcp_sock *tp = tcp_sk(sk);
555 int i;
556
557 BUG_ON(tp == NULL);
558
559 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
560 return NULL;
561
562 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900563 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
David S. Millerf8ab18d2007-09-28 15:18:35 -0700564 return &tp->md5sig_info->keys6[i].base;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800565 }
566 return NULL;
567}
568
569static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
570 struct sock *addr_sk)
571{
572 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
573}
574
575static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
576 struct request_sock *req)
577{
578 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
579}
580
581static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
582 char *newkey, u8 newkeylen)
583{
584 /* Add key to the list */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700585 struct tcp_md5sig_key *key;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800586 struct tcp_sock *tp = tcp_sk(sk);
587 struct tcp6_md5sig_key *keys;
588
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700589 key = tcp_v6_md5_do_lookup(sk, peer);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800590 if (key) {
591 /* modify existing entry - just update that one */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700592 kfree(key->key);
593 key->key = newkey;
594 key->keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800595 } else {
596 /* reallocate new list if current one is full. */
597 if (!tp->md5sig_info) {
598 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
599 if (!tp->md5sig_info) {
600 kfree(newkey);
601 return -ENOMEM;
602 }
David S. Miller3d7dbea2007-06-12 14:36:42 -0700603 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800604 }
Wu Fengguangaa133072009-09-02 23:45:45 -0700605 if (tcp_alloc_md5sig_pool(sk) == NULL) {
YOSHIFUJI Hideakiaacbe8c2007-11-20 17:30:56 -0800606 kfree(newkey);
607 return -ENOMEM;
608 }
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800609 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
610 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
611 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
612
613 if (!keys) {
614 tcp_free_md5sig_pool();
615 kfree(newkey);
616 return -ENOMEM;
617 }
618
619 if (tp->md5sig_info->entries6)
620 memmove(keys, tp->md5sig_info->keys6,
621 (sizeof (tp->md5sig_info->keys6[0]) *
622 tp->md5sig_info->entries6));
623
624 kfree(tp->md5sig_info->keys6);
625 tp->md5sig_info->keys6 = keys;
626 tp->md5sig_info->alloced6++;
627 }
628
629 ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
630 peer);
David S. Millerf8ab18d2007-09-28 15:18:35 -0700631 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
632 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800633
634 tp->md5sig_info->entries6++;
635 }
636 return 0;
637}
638
639static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
640 u8 *newkey, __u8 newkeylen)
641{
642 return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr,
643 newkey, newkeylen);
644}
645
646static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
647{
648 struct tcp_sock *tp = tcp_sk(sk);
649 int i;
650
651 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900652 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800653 /* Free the key */
David S. Millerf8ab18d2007-09-28 15:18:35 -0700654 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800655 tp->md5sig_info->entries6--;
656
657 if (tp->md5sig_info->entries6 == 0) {
658 kfree(tp->md5sig_info->keys6);
659 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700660 tp->md5sig_info->alloced6 = 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800661 } else {
662 /* shrink the database */
663 if (tp->md5sig_info->entries6 != i)
664 memmove(&tp->md5sig_info->keys6[i],
665 &tp->md5sig_info->keys6[i+1],
666 (tp->md5sig_info->entries6 - i)
667 * sizeof (tp->md5sig_info->keys6[0]));
668 }
YOSHIFUJI Hideaki77adefd2007-11-20 17:31:23 -0800669 tcp_free_md5sig_pool();
670 return 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800671 }
672 }
673 return -ENOENT;
674}
675
676static void tcp_v6_clear_md5_list (struct sock *sk)
677{
678 struct tcp_sock *tp = tcp_sk(sk);
679 int i;
680
681 if (tp->md5sig_info->entries6) {
682 for (i = 0; i < tp->md5sig_info->entries6; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700683 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800684 tp->md5sig_info->entries6 = 0;
685 tcp_free_md5sig_pool();
686 }
687
688 kfree(tp->md5sig_info->keys6);
689 tp->md5sig_info->keys6 = NULL;
690 tp->md5sig_info->alloced6 = 0;
691
692 if (tp->md5sig_info->entries4) {
693 for (i = 0; i < tp->md5sig_info->entries4; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700694 kfree(tp->md5sig_info->keys4[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800695 tp->md5sig_info->entries4 = 0;
696 tcp_free_md5sig_pool();
697 }
698
699 kfree(tp->md5sig_info->keys4);
700 tp->md5sig_info->keys4 = NULL;
701 tp->md5sig_info->alloced4 = 0;
702}
703
704static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
705 int optlen)
706{
707 struct tcp_md5sig cmd;
708 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
709 u8 *newkey;
710
711 if (optlen < sizeof(cmd))
712 return -EINVAL;
713
714 if (copy_from_user(&cmd, optval, sizeof(cmd)))
715 return -EFAULT;
716
717 if (sin6->sin6_family != AF_INET6)
718 return -EINVAL;
719
720 if (!cmd.tcpm_keylen) {
721 if (!tcp_sk(sk)->md5sig_info)
722 return -ENOENT;
Brian Haleye773e4f2007-08-24 23:16:08 -0700723 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800724 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
725 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
726 }
727
728 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
729 return -EINVAL;
730
731 if (!tcp_sk(sk)->md5sig_info) {
732 struct tcp_sock *tp = tcp_sk(sk);
733 struct tcp_md5sig_info *p;
734
735 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
736 if (!p)
737 return -ENOMEM;
738
739 tp->md5sig_info = p;
David S. Miller3d7dbea2007-06-12 14:36:42 -0700740 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800741 }
742
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200743 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800744 if (!newkey)
745 return -ENOMEM;
Brian Haleye773e4f2007-08-24 23:16:08 -0700746 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800747 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
748 newkey, cmd.tcpm_keylen);
749 }
750 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
751}
752
Adam Langley49a72df2008-07-19 00:01:42 -0700753static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
754 struct in6_addr *daddr,
755 struct in6_addr *saddr, int nbytes)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800756{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800757 struct tcp6_pseudohdr *bp;
Adam Langley49a72df2008-07-19 00:01:42 -0700758 struct scatterlist sg;
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900759
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800760 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800761 /* 1. TCP pseudo-header (RFC2460) */
762 ipv6_addr_copy(&bp->saddr, saddr);
763 ipv6_addr_copy(&bp->daddr, daddr);
Adam Langley49a72df2008-07-19 00:01:42 -0700764 bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley00b13042008-07-31 21:36:07 -0700765 bp->len = cpu_to_be32(nbytes);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800766
Adam Langley49a72df2008-07-19 00:01:42 -0700767 sg_init_one(&sg, bp, sizeof(*bp));
768 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
769}
David S. Millerc7da57a2007-10-26 00:41:21 -0700770
Adam Langley49a72df2008-07-19 00:01:42 -0700771static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
772 struct in6_addr *daddr, struct in6_addr *saddr,
773 struct tcphdr *th)
774{
775 struct tcp_md5sig_pool *hp;
776 struct hash_desc *desc;
777
778 hp = tcp_get_md5sig_pool();
779 if (!hp)
780 goto clear_hash_noput;
781 desc = &hp->md5_desc;
782
783 if (crypto_hash_init(desc))
784 goto clear_hash;
785 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
786 goto clear_hash;
787 if (tcp_md5_hash_header(hp, th))
788 goto clear_hash;
789 if (tcp_md5_hash_key(hp, key))
790 goto clear_hash;
791 if (crypto_hash_final(desc, md5_hash))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800792 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800793
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800794 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800795 return 0;
Adam Langley49a72df2008-07-19 00:01:42 -0700796
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800797clear_hash:
798 tcp_put_md5sig_pool();
799clear_hash_noput:
800 memset(md5_hash, 0, 16);
Adam Langley49a72df2008-07-19 00:01:42 -0700801 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800802}
803
Adam Langley49a72df2008-07-19 00:01:42 -0700804static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
805 struct sock *sk, struct request_sock *req,
806 struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800807{
808 struct in6_addr *saddr, *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700809 struct tcp_md5sig_pool *hp;
810 struct hash_desc *desc;
811 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800812
813 if (sk) {
814 saddr = &inet6_sk(sk)->saddr;
815 daddr = &inet6_sk(sk)->daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700816 } else if (req) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800817 saddr = &inet6_rsk(req)->loc_addr;
818 daddr = &inet6_rsk(req)->rmt_addr;
Adam Langley49a72df2008-07-19 00:01:42 -0700819 } else {
820 struct ipv6hdr *ip6h = ipv6_hdr(skb);
821 saddr = &ip6h->saddr;
822 daddr = &ip6h->daddr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800823 }
Adam Langley49a72df2008-07-19 00:01:42 -0700824
825 hp = tcp_get_md5sig_pool();
826 if (!hp)
827 goto clear_hash_noput;
828 desc = &hp->md5_desc;
829
830 if (crypto_hash_init(desc))
831 goto clear_hash;
832
833 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
834 goto clear_hash;
835 if (tcp_md5_hash_header(hp, th))
836 goto clear_hash;
837 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
838 goto clear_hash;
839 if (tcp_md5_hash_key(hp, key))
840 goto clear_hash;
841 if (crypto_hash_final(desc, md5_hash))
842 goto clear_hash;
843
844 tcp_put_md5sig_pool();
845 return 0;
846
847clear_hash:
848 tcp_put_md5sig_pool();
849clear_hash_noput:
850 memset(md5_hash, 0, 16);
851 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800852}
853
854static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
855{
856 __u8 *hash_location = NULL;
857 struct tcp_md5sig_key *hash_expected;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700858 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700859 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800860 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800861 u8 newhash[16];
862
863 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900864 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800865
David S. Miller785957d2008-07-30 03:03:15 -0700866 /* We've parsed the options - do we have a hash? */
867 if (!hash_expected && !hash_location)
868 return 0;
869
870 if (hash_expected && !hash_location) {
871 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800872 return 1;
873 }
874
David S. Miller785957d2008-07-30 03:03:15 -0700875 if (!hash_expected && hash_location) {
876 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800877 return 1;
878 }
879
880 /* check the signature */
Adam Langley49a72df2008-07-19 00:01:42 -0700881 genhash = tcp_v6_md5_hash_skb(newhash,
882 hash_expected,
883 NULL, NULL, skb);
884
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800885 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
886 if (net_ratelimit()) {
Joe Perches5856b602010-01-08 00:59:52 -0800887 printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800888 genhash ? "failed" : "mismatch",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700889 &ip6h->saddr, ntohs(th->source),
890 &ip6h->daddr, ntohs(th->dest));
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800891 }
892 return 1;
893 }
894 return 0;
895}
896#endif
897
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800898struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700900 .obj_size = sizeof(struct tcp6_request_sock),
Octavian Purdila72659ec2010-01-17 19:09:39 -0800901 .rtx_syn_ack = tcp_v6_rtx_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700902 .send_ack = tcp_v6_reqsk_send_ack,
903 .destructor = tcp_v6_reqsk_destructor,
Octavian Purdila72659ec2010-01-17 19:09:39 -0800904 .send_reset = tcp_v6_send_reset,
905 .syn_ack_timeout = tcp_syn_ack_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906};
907
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800908#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +0000909static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800910 .md5_lookup = tcp_v6_reqsk_md5_lookup,
John Dykstrae3afe7b2009-07-16 05:04:51 +0000911 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800912};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800913#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800914
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800915static struct timewait_sock_ops tcp6_timewait_sock_ops = {
916 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
917 .twsk_unique = tcp_twsk_unique,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800918 .twsk_destructor= tcp_twsk_destructor,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800919};
920
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800921static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
923 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700924 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Patrick McHardy84fa7932006-08-29 16:44:56 -0700926 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700928 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800929 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 } else {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900931 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
Joe Perches07f07572008-11-19 15:44:53 -0800932 csum_partial(th, th->doff<<2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 skb->csum));
934 }
935}
936
Herbert Xua430a432006-07-08 13:34:56 -0700937static int tcp_v6_gso_send_check(struct sk_buff *skb)
938{
939 struct ipv6hdr *ipv6h;
940 struct tcphdr *th;
941
942 if (!pskb_may_pull(skb, sizeof(*th)))
943 return -EINVAL;
944
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700945 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700946 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700947
948 th->check = 0;
949 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
950 IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700951 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800952 skb->csum_offset = offsetof(struct tcphdr, check);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700953 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xua430a432006-07-08 13:34:56 -0700954 return 0;
955}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Herbert Xu36990672009-05-22 00:45:28 -0700957static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
958 struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800959{
Herbert Xu36e7b1b2009-04-27 05:44:45 -0700960 struct ipv6hdr *iph = skb_gro_network_header(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800961
962 switch (skb->ip_summed) {
963 case CHECKSUM_COMPLETE:
Herbert Xu86911732009-01-29 14:19:50 +0000964 if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
Herbert Xu684f2172009-01-08 10:41:23 -0800965 skb->csum)) {
966 skb->ip_summed = CHECKSUM_UNNECESSARY;
967 break;
968 }
969
970 /* fall through */
971 case CHECKSUM_NONE:
972 NAPI_GRO_CB(skb)->flush = 1;
973 return NULL;
974 }
975
976 return tcp_gro_receive(head, skb);
977}
Herbert Xu684f2172009-01-08 10:41:23 -0800978
Herbert Xu36990672009-05-22 00:45:28 -0700979static int tcp6_gro_complete(struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800980{
981 struct ipv6hdr *iph = ipv6_hdr(skb);
982 struct tcphdr *th = tcp_hdr(skb);
983
984 th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
985 &iph->saddr, &iph->daddr, 0);
986 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
987
988 return tcp_gro_complete(skb);
989}
Herbert Xu684f2172009-01-08 10:41:23 -0800990
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700991static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
992 u32 ts, struct tcp_md5sig_key *key, int rst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700994 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 struct sk_buff *buff;
996 struct flowi fl;
Eric Dumazetadf30902009-06-02 05:19:30 +0000997 struct net *net = dev_net(skb_dst(skb)->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -0800998 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -0800999 unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazetadf30902009-06-02 05:19:30 +00001000 struct dst_entry *dst;
Al Viroe69a4ad2006-11-14 20:56:00 -08001001 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -07001004 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001005#ifdef CONFIG_TCP_MD5SIG
1006 if (key)
1007 tot_len += TCPOLEN_MD5SIG_ALIGNED;
1008#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
1011 GFP_ATOMIC);
1012 if (buff == NULL)
1013 return;
1014
1015 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
1016
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001017 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Herbert Xu6651ffc2010-04-21 00:47:15 -07001018 skb_reset_transport_header(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 /* Swap the send and the receive. */
1021 memset(t1, 0, sizeof(*t1));
1022 t1->dest = th->source;
1023 t1->source = th->dest;
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001024 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 t1->seq = htonl(seq);
1026 t1->ack_seq = htonl(ack);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001027 t1->ack = !rst || !th->ack;
1028 t1->rst = rst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001030
Al Viroe69a4ad2006-11-14 20:56:00 -08001031 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001034 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1035 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
1036 *topt++ = htonl(tcp_time_stamp);
Ilpo Järvinen53b12572008-10-08 14:36:33 -07001037 *topt++ = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
1039
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001040#ifdef CONFIG_TCP_MD5SIG
1041 if (key) {
1042 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1043 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Adam Langley49a72df2008-07-19 00:01:42 -07001044 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
Adam Langley90b7e112008-07-31 20:49:48 -07001045 &ipv6_hdr(skb)->saddr,
1046 &ipv6_hdr(skb)->daddr, t1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001047 }
1048#endif
1049
Joe Perches07f07572008-11-19 15:44:53 -08001050 buff->csum = csum_partial(t1, tot_len, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001053 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1054 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
1056 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
1057 tot_len, IPPROTO_TCP,
1058 buff->csum);
1059
1060 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001061 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 fl.fl_ip_dport = t1->dest;
1063 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001064 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001066 /* Pass a socket to ip6_dst_lookup either it is for RST
1067 * Underlying function will use this to retrieve the network
1068 * namespace
1069 */
Eric Dumazetadf30902009-06-02 05:19:30 +00001070 if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
1071 if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
1072 skb_dst_set(buff, dst);
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001073 ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001074 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001075 if (rst)
1076 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080
1081 kfree_skb(buff);
1082}
1083
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001084static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
1085{
1086 struct tcphdr *th = tcp_hdr(skb);
1087 u32 seq = 0, ack_seq = 0;
Guo-Fu Tsengfa3e5b42008-10-09 21:11:56 -07001088 struct tcp_md5sig_key *key = NULL;
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001089
1090 if (th->rst)
1091 return;
1092
1093 if (!ipv6_unicast_destination(skb))
1094 return;
1095
1096#ifdef CONFIG_TCP_MD5SIG
1097 if (sk)
1098 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001099#endif
1100
1101 if (th->ack)
1102 seq = ntohl(th->ack_seq);
1103 else
1104 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
1105 (th->doff << 2);
1106
1107 tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1);
1108}
1109
1110static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
1111 struct tcp_md5sig_key *key)
1112{
1113 tcp_v6_send_response(skb, seq, ack, win, ts, key, 0);
1114}
1115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1117{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001118 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001119 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001121 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001122 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001123 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001125 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126}
1127
Gui Jianfeng6edafaa2008-08-06 23:50:04 -07001128static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
1129 struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001131 tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
Gui Jianfeng6edafaa2008-08-06 23:50:04 -07001132 tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133}
1134
1135
1136static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1137{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001138 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001139 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 struct sock *nsk;
1141
1142 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001143 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001144 &ipv6_hdr(skb)->saddr,
1145 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (req)
1147 return tcp_check_req(sk, skb, req, prev);
1148
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001149 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001150 &ipv6_hdr(skb)->saddr, th->source,
1151 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 if (nsk) {
1154 if (nsk->sk_state != TCP_TIME_WAIT) {
1155 bh_lock_sock(nsk);
1156 return nsk;
1157 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001158 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 return NULL;
1160 }
1161
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001162#ifdef CONFIG_SYN_COOKIES
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 if (!th->rst && !th->syn && th->ack)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001164 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165#endif
1166 return sk;
1167}
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169/* FIXME: this is substantially similar to the ipv4 code.
1170 * Can some kind of merge be done? -- erics
1171 */
1172static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1173{
William Allen Simpson4957faa2009-12-02 18:25:27 +00001174 struct tcp_extend_values tmp_ext;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001175 struct tcp_options_received tmp_opt;
William Allen Simpson4957faa2009-12-02 18:25:27 +00001176 u8 *hash_location;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001177 struct request_sock *req;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001178 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 struct ipv6_pinfo *np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 struct tcp_sock *tp = tcp_sk(sk);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001181 __u32 isn = TCP_SKB_CB(skb)->when;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001182#ifdef CONFIG_SYN_COOKIES
1183 int want_cookie = 0;
1184#else
1185#define want_cookie 0
1186#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 if (skb->protocol == htons(ETH_P_IP))
1189 return tcp_v4_conn_request(sk, skb);
1190
1191 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001192 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001194 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (net_ratelimit())
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001196 syn_flood_warning(skb);
1197#ifdef CONFIG_SYN_COOKIES
1198 if (sysctl_tcp_syncookies)
1199 want_cookie = 1;
1200 else
1201#endif
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001202 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
1204
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001205 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 goto drop;
1207
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001208 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 if (req == NULL)
1210 goto drop;
1211
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001212#ifdef CONFIG_TCP_MD5SIG
1213 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1214#endif
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 tcp_clear_options(&tmp_opt);
1217 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1218 tmp_opt.user_mss = tp->rx_opt.user_mss;
David S. Millerbb5b7c12009-12-15 20:56:42 -08001219 tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
William Allen Simpson4957faa2009-12-02 18:25:27 +00001221 if (tmp_opt.cookie_plus > 0 &&
1222 tmp_opt.saw_tstamp &&
1223 !tp->rx_opt.cookie_out_never &&
1224 (sysctl_tcp_cookie_size > 0 ||
1225 (tp->cookie_values != NULL &&
1226 tp->cookie_values->cookie_desired > 0))) {
1227 u8 *c;
1228 u32 *d;
1229 u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
1230 int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
1231
1232 if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
1233 goto drop_and_free;
1234
1235 /* Secret recipe starts with IP addresses */
1236 d = &ipv6_hdr(skb)->daddr.s6_addr32[0];
1237 *mess++ ^= *d++;
1238 *mess++ ^= *d++;
1239 *mess++ ^= *d++;
1240 *mess++ ^= *d++;
1241 d = &ipv6_hdr(skb)->saddr.s6_addr32[0];
1242 *mess++ ^= *d++;
1243 *mess++ ^= *d++;
1244 *mess++ ^= *d++;
1245 *mess++ ^= *d++;
1246
1247 /* plus variable length Initiator Cookie */
1248 c = (u8 *)mess;
1249 while (l-- > 0)
1250 *c++ ^= *hash_location++;
1251
1252#ifdef CONFIG_SYN_COOKIES
1253 want_cookie = 0; /* not our kind of cookie */
1254#endif
1255 tmp_ext.cookie_out_never = 0; /* false */
1256 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1257 } else if (!tp->rx_opt.cookie_in_always) {
1258 /* redundant indications, but ensure initialization. */
1259 tmp_ext.cookie_out_never = 1; /* true */
1260 tmp_ext.cookie_plus = 0;
1261 } else {
1262 goto drop_and_free;
1263 }
1264 tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Florian Westphal4dfc2812008-04-10 03:12:40 -07001266 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001267 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001268
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1270 tcp_openreq_init(req, &tmp_opt, skb);
1271
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001272 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001273 ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
1274 ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001275 if (!want_cookie)
1276 TCP_ECN_create_request(req, tcp_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001278 if (want_cookie) {
1279 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
Florian Westphal4dfc2812008-04-10 03:12:40 -07001280 req->cookie_ts = tmp_opt.tstamp_ok;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001281 } else if (!isn) {
1282 if (ipv6_opt_accepted(sk, skb) ||
1283 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1284 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1285 atomic_inc(&skb->users);
1286 treq->pktopts = skb;
1287 }
1288 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001290 /* So that link locals have meaning */
1291 if (!sk->sk_bound_dev_if &&
1292 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1293 treq->iif = inet6_iif(skb);
1294
Gerrit Renkera94f7232006-11-10 14:06:49 -08001295 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001296 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001297 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001299 security_inet_conn_request(sk, skb, req);
1300
William Allen Simpson4957faa2009-12-02 18:25:27 +00001301 if (tcp_v6_send_synack(sk, req,
1302 (struct request_values *)&tmp_ext) ||
1303 want_cookie)
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001304 goto drop_and_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001306 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1307 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001309drop_and_free:
1310 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311drop:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 return 0; /* don't send reset */
1313}
1314
1315static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001316 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 struct dst_entry *dst)
1318{
Vegard Nossum78d15e82008-09-12 16:17:43 -07001319 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1321 struct tcp6_sock *newtcp6sk;
1322 struct inet_sock *newinet;
1323 struct tcp_sock *newtp;
1324 struct sock *newsk;
1325 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001326#ifdef CONFIG_TCP_MD5SIG
1327 struct tcp_md5sig_key *key;
1328#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
1330 if (skb->protocol == htons(ETH_P_IP)) {
1331 /*
1332 * v6 mapped
1333 */
1334
1335 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1336
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001337 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 return NULL;
1339
1340 newtcp6sk = (struct tcp6_sock *)newsk;
1341 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1342
1343 newinet = inet_sk(newsk);
1344 newnp = inet6_sk(newsk);
1345 newtp = tcp_sk(newsk);
1346
1347 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1348
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001349 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001351 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
1353 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1354
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001355 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001357#ifdef CONFIG_TCP_MD5SIG
1358 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1359#endif
1360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 newnp->pktoptions = NULL;
1362 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001363 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001364 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001366 /*
1367 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1368 * here, tcp_create_openreq_child now does this for us, see the comment in
1369 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001373 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 Sync it now.
1375 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001376 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 return newsk;
1379 }
1380
Vegard Nossum78d15e82008-09-12 16:17:43 -07001381 treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 opt = np->opt;
1383
1384 if (sk_acceptq_is_full(sk))
1385 goto out_overflow;
1386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 if (dst == NULL) {
1388 struct in6_addr *final_p = NULL, final;
1389 struct flowi fl;
1390
1391 memset(&fl, 0, sizeof(fl));
1392 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001393 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 if (opt && opt->srcrt) {
1395 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
1396 ipv6_addr_copy(&final, &fl.fl6_dst);
1397 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1398 final_p = &final;
1399 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001400 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 fl.oif = sk->sk_bound_dev_if;
Brian Haley51953d52009-10-05 08:24:16 +00001402 fl.mark = sk->sk_mark;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001403 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
KOVACS Krisztianfd507032008-10-19 23:35:58 -07001404 fl.fl_ip_sport = inet_rsk(req)->loc_port;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001405 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
1407 if (ip6_dst_lookup(sk, &dst, &fl))
1408 goto out;
1409
1410 if (final_p)
1411 ipv6_addr_copy(&fl.fl6_dst, final_p);
1412
Alexey Dobriyan52479b62008-11-25 17:35:18 -08001413 if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
1417 newsk = tcp_create_openreq_child(sk, req, skb);
1418 if (newsk == NULL)
1419 goto out;
1420
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001421 /*
1422 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1423 * count here, tcp_create_openreq_child now does this for us, see the
1424 * comment in that function for the gory details. -acme
1425 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
Stephen Hemminger59eed272006-08-25 15:55:43 -07001427 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001428 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
1430 newtcp6sk = (struct tcp6_sock *)newsk;
1431 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1432
1433 newtp = tcp_sk(newsk);
1434 newinet = inet_sk(newsk);
1435 newnp = inet6_sk(newsk);
1436
1437 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1438
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001439 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1440 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1441 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1442 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001444 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
1446 First: no IPv4 options.
1447 */
1448 newinet->opt = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001449 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
1451 /* Clone RX bits */
1452 newnp->rxopt.all = np->rxopt.all;
1453
1454 /* Clone pktoptions received with SYN */
1455 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001456 if (treq->pktopts != NULL) {
1457 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1458 kfree_skb(treq->pktopts);
1459 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 if (newnp->pktoptions)
1461 skb_set_owner_r(newnp->pktoptions, newsk);
1462 }
1463 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001464 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001465 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
1467 /* Clone native IPv6 options from listening socket (if any)
1468
1469 Yes, keeping reference count would be much more clever,
1470 but we make one more one thing there: reattach optmem
1471 to newsk.
1472 */
1473 if (opt) {
1474 newnp->opt = ipv6_dup_options(newsk, opt);
1475 if (opt != np->opt)
1476 sock_kfree_s(sk, opt, opt->tot_len);
1477 }
1478
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001479 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001481 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1482 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
John Heffner5d424d52006-03-20 17:53:41 -08001484 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 tcp_sync_mss(newsk, dst_mtu(dst));
1486 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1487 tcp_initialize_rcv_mss(newsk);
1488
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001489 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
1490 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001492#ifdef CONFIG_TCP_MD5SIG
1493 /* Copy over the MD5 key from the original socket */
1494 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1495 /* We're using one, so create a matching key
1496 * on the newsk structure. If we fail to get
1497 * memory, then we end up not copying the key
1498 * across. Shucks.
1499 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001500 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1501 if (newkey != NULL)
John Dykstrae547bc12009-07-17 09:23:22 +00001502 tcp_v6_md5_do_add(newsk, &newnp->daddr,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001503 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001504 }
1505#endif
1506
Eric Dumazet9327f702009-12-04 03:46:54 +00001507 __inet6_hash(newsk, NULL);
Pavel Emelyanove56d8b82008-04-17 23:17:34 -07001508 __inet_inherit_port(sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
1510 return newsk;
1511
1512out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001513 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514out:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001515 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 if (opt && opt != np->opt)
1517 sock_kfree_s(sk, opt, opt->tot_len);
1518 dst_release(dst);
1519 return NULL;
1520}
1521
Al Virob51655b2006-11-14 21:40:42 -08001522static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001524 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Herbert Xu684f2172009-01-08 10:41:23 -08001525 if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001526 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001527 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001531
Herbert Xu684f2172009-01-08 10:41:23 -08001532 skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001533 &ipv6_hdr(skb)->saddr,
1534 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001535
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001537 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 }
1539 return 0;
1540}
1541
1542/* The socket must have it's spinlock held when we get
1543 * here.
1544 *
1545 * We have a potential double-lock case here, so even when
1546 * doing backlog processing we use the BH locking scheme.
1547 * This is because we cannot sleep with the original spinlock
1548 * held.
1549 */
1550static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1551{
1552 struct ipv6_pinfo *np = inet6_sk(sk);
1553 struct tcp_sock *tp;
1554 struct sk_buff *opt_skb = NULL;
1555
1556 /* Imagine: socket is IPv6. IPv4 packet arrives,
1557 goes to IPv4 receive handler and backlogged.
1558 From backlog it always goes here. Kerboom...
1559 Fortunately, tcp_rcv_established and rcv_established
1560 handle them correctly, but it is not case with
1561 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1562 */
1563
1564 if (skb->protocol == htons(ETH_P_IP))
1565 return tcp_v4_do_rcv(sk, skb);
1566
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001567#ifdef CONFIG_TCP_MD5SIG
1568 if (tcp_v6_inbound_md5_hash (sk, skb))
1569 goto discard;
1570#endif
1571
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001572 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 goto discard;
1574
1575 /*
1576 * socket locking is here for SMP purposes as backlog rcv
1577 * is currently called with bh processing disabled.
1578 */
1579
1580 /* Do Stevens' IPV6_PKTOPTIONS.
1581
1582 Yes, guys, it is the only place in our code, where we
1583 may make it not affecting IPv4.
1584 The rest of code is protocol independent,
1585 and I do not like idea to uglify IPv4.
1586
1587 Actually, all the idea behind IPV6_PKTOPTIONS
1588 looks not very well thought. For now we latch
1589 options, received in the last packet, enqueued
1590 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001591 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 */
1593 if (np->rxopt.all)
1594 opt_skb = skb_clone(skb, GFP_ATOMIC);
1595
1596 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1597 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001598 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 goto reset;
1600 TCP_CHECK_TIMER(sk);
1601 if (opt_skb)
1602 goto ipv6_pktoptions;
1603 return 0;
1604 }
1605
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001606 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 goto csum_err;
1608
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001609 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1611 if (!nsk)
1612 goto discard;
1613
1614 /*
1615 * Queue it on the new socket if the new socket is active,
1616 * otherwise we just shortcircuit this and continue with
1617 * the new socket..
1618 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001619 if(nsk != sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 if (tcp_child_process(sk, nsk, skb))
1621 goto reset;
1622 if (opt_skb)
1623 __kfree_skb(opt_skb);
1624 return 0;
1625 }
1626 }
1627
1628 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001629 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 goto reset;
1631 TCP_CHECK_TIMER(sk);
1632 if (opt_skb)
1633 goto ipv6_pktoptions;
1634 return 0;
1635
1636reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001637 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638discard:
1639 if (opt_skb)
1640 __kfree_skb(opt_skb);
1641 kfree_skb(skb);
1642 return 0;
1643csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001644 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 goto discard;
1646
1647
1648ipv6_pktoptions:
1649 /* Do you ask, what is it?
1650
1651 1. skb was enqueued by tcp.
1652 2. skb is added to tail of read queue, rather than out of order.
1653 3. socket is not in passive state.
1654 4. Finally, it really contains options, which user wants to receive.
1655 */
1656 tp = tcp_sk(sk);
1657 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1658 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001659 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001660 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001661 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001662 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 if (ipv6_opt_accepted(sk, opt_skb)) {
1664 skb_set_owner_r(opt_skb, sk);
1665 opt_skb = xchg(&np->pktoptions, opt_skb);
1666 } else {
1667 __kfree_skb(opt_skb);
1668 opt_skb = xchg(&np->pktoptions, NULL);
1669 }
1670 }
1671
Wei Yongjun800d55f2009-02-23 21:45:33 +00001672 kfree_skb(opt_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 return 0;
1674}
1675
Herbert Xue5bbef22007-10-15 12:50:28 -07001676static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677{
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001678 struct tcphdr *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 struct sock *sk;
1680 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001681 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 if (skb->pkt_type != PACKET_HOST)
1684 goto discard_it;
1685
1686 /*
1687 * Count it even if it's bad.
1688 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001689 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1692 goto discard_it;
1693
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001694 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 if (th->doff < sizeof(struct tcphdr)/4)
1697 goto bad_packet;
1698 if (!pskb_may_pull(skb, th->doff*4))
1699 goto discard_it;
1700
Herbert Xu60476372007-04-09 11:59:39 -07001701 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 goto bad_packet;
1703
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001704 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1706 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1707 skb->len - th->doff*4);
1708 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1709 TCP_SKB_CB(skb)->when = 0;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001710 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 TCP_SKB_CB(skb)->sacked = 0;
1712
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -07001713 sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if (!sk)
1715 goto no_tcp_socket;
1716
1717process:
1718 if (sk->sk_state == TCP_TIME_WAIT)
1719 goto do_time_wait;
1720
1721 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1722 goto discard_and_relse;
1723
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001724 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 goto discard_and_relse;
1726
1727 skb->dev = NULL;
1728
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001729 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 ret = 0;
1731 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001732#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001733 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001734 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
Dan Williamsf67b4592009-01-06 11:38:15 -07001735 tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001736 if (tp->ucopy.dma_chan)
1737 ret = tcp_v6_do_rcv(sk, skb);
1738 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001739#endif
1740 {
1741 if (!tcp_prequeue(sk, skb))
1742 ret = tcp_v6_do_rcv(sk, skb);
1743 }
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001744 } else if (unlikely(sk_add_backlog(sk, skb))) {
Zhu Yi6b03a532010-03-04 18:01:41 +00001745 bh_unlock_sock(sk);
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001746 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
Zhu Yi6b03a532010-03-04 18:01:41 +00001747 goto discard_and_relse;
1748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 bh_unlock_sock(sk);
1750
1751 sock_put(sk);
1752 return ret ? -1 : 0;
1753
1754no_tcp_socket:
1755 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1756 goto discard_it;
1757
1758 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1759bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001760 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001762 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 }
1764
1765discard_it:
1766
1767 /*
1768 * Discard frame
1769 */
1770
1771 kfree_skb(skb);
1772 return 0;
1773
1774discard_and_relse:
1775 sock_put(sk);
1776 goto discard_it;
1777
1778do_time_wait:
1779 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001780 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 goto discard_it;
1782 }
1783
1784 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001785 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001786 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 goto discard_it;
1788 }
1789
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001790 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 case TCP_TW_SYN:
1792 {
1793 struct sock *sk2;
1794
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001795 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001796 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001797 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001799 struct inet_timewait_sock *tw = inet_twsk(sk);
1800 inet_twsk_deschedule(tw, &tcp_death_row);
1801 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 sk = sk2;
1803 goto process;
1804 }
1805 /* Fall through to ACK */
1806 }
1807 case TCP_TW_ACK:
1808 tcp_v6_timewait_ack(sk, skb);
1809 break;
1810 case TCP_TW_RST:
1811 goto no_tcp_socket;
1812 case TCP_TW_SUCCESS:;
1813 }
1814 goto discard_it;
1815}
1816
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817static int tcp_v6_remember_stamp(struct sock *sk)
1818{
1819 /* Alas, not yet... */
1820 return 0;
1821}
1822
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001823static const struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001824 .queue_xmit = inet6_csk_xmit,
1825 .send_check = tcp_v6_send_check,
1826 .rebuild_header = inet6_sk_rebuild_header,
1827 .conn_request = tcp_v6_conn_request,
1828 .syn_recv_sock = tcp_v6_syn_recv_sock,
1829 .remember_stamp = tcp_v6_remember_stamp,
1830 .net_header_len = sizeof(struct ipv6hdr),
1831 .setsockopt = ipv6_setsockopt,
1832 .getsockopt = ipv6_getsockopt,
1833 .addr2sockaddr = inet6_csk_addr2sockaddr,
1834 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001835 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001836#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001837 .compat_setsockopt = compat_ipv6_setsockopt,
1838 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001839#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840};
1841
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001842#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001843static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001844 .md5_lookup = tcp_v6_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001845 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001846 .md5_add = tcp_v6_md5_add_func,
1847 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001848};
David S. Millera9286302006-11-14 19:53:22 -08001849#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001850
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851/*
1852 * TCP over IPv4 via INET6 API
1853 */
1854
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001855static const struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001856 .queue_xmit = ip_queue_xmit,
1857 .send_check = tcp_v4_send_check,
1858 .rebuild_header = inet_sk_rebuild_header,
1859 .conn_request = tcp_v6_conn_request,
1860 .syn_recv_sock = tcp_v6_syn_recv_sock,
1861 .remember_stamp = tcp_v4_remember_stamp,
1862 .net_header_len = sizeof(struct iphdr),
1863 .setsockopt = ipv6_setsockopt,
1864 .getsockopt = ipv6_getsockopt,
1865 .addr2sockaddr = inet6_csk_addr2sockaddr,
1866 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001867 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001868#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001869 .compat_setsockopt = compat_ipv6_setsockopt,
1870 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001871#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872};
1873
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001874#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001875static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001876 .md5_lookup = tcp_v4_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001877 .calc_md5_hash = tcp_v4_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001878 .md5_add = tcp_v6_md5_add_func,
1879 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001880};
David S. Millera9286302006-11-14 19:53:22 -08001881#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001882
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883/* NOTE: A lot of things set to zero explicitly by call to
1884 * sk_alloc() so need not be done here.
1885 */
1886static int tcp_v6_init_sock(struct sock *sk)
1887{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001888 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 struct tcp_sock *tp = tcp_sk(sk);
1890
1891 skb_queue_head_init(&tp->out_of_order_queue);
1892 tcp_init_xmit_timers(sk);
1893 tcp_prequeue_init(tp);
1894
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001895 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 tp->mdev = TCP_TIMEOUT_INIT;
1897
1898 /* So many TCP implementations out there (incorrectly) count the
1899 * initial SYN frame in their delayed-ACK and congestion control
1900 * algorithms that we must have the following bandaid to talk
1901 * efficiently to them. -DaveM
1902 */
1903 tp->snd_cwnd = 2;
1904
1905 /* See draft-stevens-tcpca-spec-01 for discussion of the
1906 * initialization of these values.
1907 */
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07001908 tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 tp->snd_cwnd_clamp = ~0;
William Allen Simpsonbee7ca92009-11-10 09:51:18 +00001910 tp->mss_cache = TCP_MSS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
1912 tp->reordering = sysctl_tcp_reordering;
1913
1914 sk->sk_state = TCP_CLOSE;
1915
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001916 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001917 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001918 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 sk->sk_write_space = sk_stream_write_space;
1920 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1921
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001922#ifdef CONFIG_TCP_MD5SIG
1923 tp->af_specific = &tcp_sock_ipv6_specific;
1924#endif
1925
William Allen Simpson435cf552009-12-02 18:17:05 +00001926 /* TCP Cookie Transactions */
1927 if (sysctl_tcp_cookie_size > 0) {
1928 /* Default, cookies without s_data_payload. */
1929 tp->cookie_values =
1930 kzalloc(sizeof(*tp->cookie_values),
1931 sk->sk_allocation);
1932 if (tp->cookie_values != NULL)
1933 kref_init(&tp->cookie_values->kref);
1934 }
1935 /* Presumed zeroed, in order of appearance:
1936 * cookie_in_always, cookie_out_never,
1937 * s_data_constant, s_data_in, s_data_out
1938 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1940 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1941
Herbert Xueb4dea52008-12-29 23:04:08 -08001942 local_bh_disable();
Eric Dumazet17483762008-11-25 21:16:35 -08001943 percpu_counter_inc(&tcp_sockets_allocated);
Herbert Xueb4dea52008-12-29 23:04:08 -08001944 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
1946 return 0;
1947}
1948
Brian Haley7d06b2e2008-06-14 17:04:49 -07001949static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001951#ifdef CONFIG_TCP_MD5SIG
1952 /* Clean up the MD5 key list */
1953 if (tcp_sk(sk)->md5sig_info)
1954 tcp_v6_clear_md5_list(sk);
1955#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001957 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958}
1959
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09001960#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001962static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001963 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001966 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1967 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
1969 if (ttd < 0)
1970 ttd = 0;
1971
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 seq_printf(seq,
1973 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1974 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1975 i,
1976 src->s6_addr32[0], src->s6_addr32[1],
1977 src->s6_addr32[2], src->s6_addr32[3],
KOVACS Krisztianfd507032008-10-19 23:35:58 -07001978 ntohs(inet_rsk(req)->loc_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 dest->s6_addr32[0], dest->s6_addr32[1],
1980 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001981 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 TCP_SYN_RECV,
1983 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001984 1, /* timers active (only the expire timer) */
1985 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 req->retrans,
1987 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001988 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 0, /* open_requests have no inode */
1990 0, req);
1991}
1992
1993static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1994{
1995 struct in6_addr *dest, *src;
1996 __u16 destp, srcp;
1997 int timer_active;
1998 unsigned long timer_expires;
1999 struct inet_sock *inet = inet_sk(sp);
2000 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002001 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 struct ipv6_pinfo *np = inet6_sk(sp);
2003
2004 dest = &np->daddr;
2005 src = &np->rcv_saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +00002006 destp = ntohs(inet->inet_dport);
2007 srcp = ntohs(inet->inet_sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002008
2009 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002011 timer_expires = icsk->icsk_timeout;
2012 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002014 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 } else if (timer_pending(&sp->sk_timer)) {
2016 timer_active = 2;
2017 timer_expires = sp->sk_timer.expires;
2018 } else {
2019 timer_active = 0;
2020 timer_expires = jiffies;
2021 }
2022
2023 seq_printf(seq,
2024 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Stephen Hemminger7be87352008-06-27 20:00:19 -07002025 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 i,
2027 src->s6_addr32[0], src->s6_addr32[1],
2028 src->s6_addr32[2], src->s6_addr32[3], srcp,
2029 dest->s6_addr32[0], dest->s6_addr32[1],
2030 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002031 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07002032 tp->write_seq-tp->snd_una,
2033 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 timer_active,
2035 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002036 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03002038 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 sock_i_ino(sp),
2040 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07002041 jiffies_to_clock_t(icsk->icsk_rto),
2042 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002043 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07002044 tp->snd_cwnd,
2045 tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 );
2047}
2048
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002049static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07002050 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051{
2052 struct in6_addr *dest, *src;
2053 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002054 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 int ttd = tw->tw_ttd - jiffies;
2056
2057 if (ttd < 0)
2058 ttd = 0;
2059
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002060 dest = &tw6->tw_v6_daddr;
2061 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 destp = ntohs(tw->tw_dport);
2063 srcp = ntohs(tw->tw_sport);
2064
2065 seq_printf(seq,
2066 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
2067 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
2068 i,
2069 src->s6_addr32[0], src->s6_addr32[1],
2070 src->s6_addr32[2], src->s6_addr32[3], srcp,
2071 dest->s6_addr32[0], dest->s6_addr32[1],
2072 dest->s6_addr32[2], dest->s6_addr32[3], destp,
2073 tw->tw_substate, 0, 0,
2074 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
2075 atomic_read(&tw->tw_refcnt), tw);
2076}
2077
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078static int tcp6_seq_show(struct seq_file *seq, void *v)
2079{
2080 struct tcp_iter_state *st;
2081
2082 if (v == SEQ_START_TOKEN) {
2083 seq_puts(seq,
2084 " sl "
2085 "local_address "
2086 "remote_address "
2087 "st tx_queue rx_queue tr tm->when retrnsmt"
2088 " uid timeout inode\n");
2089 goto out;
2090 }
2091 st = seq->private;
2092
2093 switch (st->state) {
2094 case TCP_SEQ_STATE_LISTENING:
2095 case TCP_SEQ_STATE_ESTABLISHED:
2096 get_tcp6_sock(seq, v, st->num);
2097 break;
2098 case TCP_SEQ_STATE_OPENREQ:
2099 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
2100 break;
2101 case TCP_SEQ_STATE_TIME_WAIT:
2102 get_timewait6_sock(seq, v, st->num);
2103 break;
2104 }
2105out:
2106 return 0;
2107}
2108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 .name = "tcp6",
2111 .family = AF_INET6,
Denis V. Lunev5f4472c2008-04-13 22:13:53 -07002112 .seq_fops = {
2113 .owner = THIS_MODULE,
2114 },
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07002115 .seq_ops = {
2116 .show = tcp6_seq_show,
2117 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118};
2119
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002120int __net_init tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002122 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123}
2124
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002125void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002127 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128}
2129#endif
2130
2131struct proto tcpv6_prot = {
2132 .name = "TCPv6",
2133 .owner = THIS_MODULE,
2134 .close = tcp_close,
2135 .connect = tcp_v6_connect,
2136 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002137 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 .ioctl = tcp_ioctl,
2139 .init = tcp_v6_init_sock,
2140 .destroy = tcp_v6_destroy_sock,
2141 .shutdown = tcp_shutdown,
2142 .setsockopt = tcp_setsockopt,
2143 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 .recvmsg = tcp_recvmsg,
2145 .backlog_rcv = tcp_v6_do_rcv,
2146 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08002147 .unhash = inet_unhash,
2148 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 .enter_memory_pressure = tcp_enter_memory_pressure,
2150 .sockets_allocated = &tcp_sockets_allocated,
2151 .memory_allocated = &tcp_memory_allocated,
2152 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002153 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 .sysctl_mem = sysctl_tcp_mem,
2155 .sysctl_wmem = sysctl_tcp_wmem,
2156 .sysctl_rmem = sysctl_tcp_rmem,
2157 .max_header = MAX_TCP_HEADER,
2158 .obj_size = sizeof(struct tcp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08002159 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002160 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002161 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002162 .h.hashinfo = &tcp_hashinfo,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002163#ifdef CONFIG_COMPAT
2164 .compat_setsockopt = compat_tcp_setsockopt,
2165 .compat_getsockopt = compat_tcp_getsockopt,
2166#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167};
2168
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00002169static const struct inet6_protocol tcpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 .handler = tcp_v6_rcv,
2171 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002172 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002173 .gso_segment = tcp_tso_segment,
Herbert Xu684f2172009-01-08 10:41:23 -08002174 .gro_receive = tcp6_gro_receive,
2175 .gro_complete = tcp6_gro_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2177};
2178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179static struct inet_protosw tcpv6_protosw = {
2180 .type = SOCK_STREAM,
2181 .protocol = IPPROTO_TCP,
2182 .prot = &tcpv6_prot,
2183 .ops = &inet6_stream_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002185 .flags = INET_PROTOSW_PERMANENT |
2186 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187};
2188
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002189static int __net_init tcpv6_net_init(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002190{
Denis V. Lunev56772422008-04-03 14:28:30 -07002191 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2192 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002193}
2194
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002195static void __net_exit tcpv6_net_exit(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002196{
Denis V. Lunev56772422008-04-03 14:28:30 -07002197 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002198}
2199
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002200static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002201{
2202 inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002203}
2204
2205static struct pernet_operations tcpv6_net_ops = {
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002206 .init = tcpv6_net_init,
2207 .exit = tcpv6_net_exit,
2208 .exit_batch = tcpv6_net_exit_batch,
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002209};
2210
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002211int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002213 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002214
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002215 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2216 if (ret)
2217 goto out;
2218
2219 /* register inet6 protocol */
2220 ret = inet6_register_protosw(&tcpv6_protosw);
2221 if (ret)
2222 goto out_tcpv6_protocol;
2223
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002224 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002225 if (ret)
2226 goto out_tcpv6_protosw;
2227out:
2228 return ret;
2229
2230out_tcpv6_protocol:
2231 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2232out_tcpv6_protosw:
2233 inet6_unregister_protosw(&tcpv6_protosw);
2234 goto out;
2235}
2236
Daniel Lezcano09f77092007-12-13 05:34:58 -08002237void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002238{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002239 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002240 inet6_unregister_protosw(&tcpv6_protosw);
2241 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242}