blob: 1d0ab5570904fd83bcf9063aa53e986567063e3f [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);
Herbert Xu8ad50d92010-04-11 02:15:54 +000078static void __tcp_v6_send_check(struct sk_buff *skb,
79 struct in6_addr *saddr,
80 struct in6_addr *daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Stephen Hemminger3b401a82009-09-01 19:25:04 +000082static const struct inet_connection_sock_af_ops ipv6_mapped;
83static const struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080084#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +000085static const struct tcp_sock_af_ops tcp_sock_ipv6_specific;
86static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090087#else
88static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
89 struct in6_addr *addr)
90{
91 return NULL;
92}
David S. Millera9286302006-11-14 19:53:22 -080093#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static void tcp_v6_hash(struct sock *sk)
96{
97 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080098 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 tcp_prot.hash(sk);
100 return;
101 }
102 local_bh_disable();
Eric Dumazet9327f702009-12-04 03:46:54 +0000103 __inet6_hash(sk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 local_bh_enable();
105 }
106}
107
Herbert Xu684f2172009-01-08 10:41:23 -0800108static __inline__ __sum16 tcp_v6_check(int len,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900109 struct in6_addr *saddr,
110 struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800111 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
113 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
114}
115
Gerrit Renkera94f7232006-11-10 14:06:49 -0800116static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700118 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
119 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700120 tcp_hdr(skb)->dest,
121 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900124static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 int addr_len)
126{
127 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900128 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800129 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct ipv6_pinfo *np = inet6_sk(sk);
131 struct tcp_sock *tp = tcp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000132 struct in6_addr *saddr = NULL, *final_p, final;
David S. Miller493f3772010-12-02 12:14:29 -0800133 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct flowi fl;
135 struct dst_entry *dst;
136 int addr_type;
137 int err;
138
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900139 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 return -EINVAL;
141
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900142 if (usin->sin6_family != AF_INET6)
Eric Dumazeta02cec22010-09-22 20:43:57 +0000143 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145 memset(&fl, 0, sizeof(fl));
146
147 if (np->sndflow) {
148 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
149 IP6_ECN_flow_init(fl.fl6_flowlabel);
150 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
151 struct ip6_flowlabel *flowlabel;
152 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
153 if (flowlabel == NULL)
154 return -EINVAL;
155 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
156 fl6_sock_release(flowlabel);
157 }
158 }
159
160 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900161 * connect() to INADDR_ANY means loopback (BSD'ism).
162 */
163
164 if(ipv6_addr_any(&usin->sin6_addr))
165 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 addr_type = ipv6_addr_type(&usin->sin6_addr);
168
169 if(addr_type & IPV6_ADDR_MULTICAST)
170 return -ENETUNREACH;
171
172 if (addr_type&IPV6_ADDR_LINKLOCAL) {
173 if (addr_len >= sizeof(struct sockaddr_in6) &&
174 usin->sin6_scope_id) {
175 /* If interface is set while binding, indices
176 * must coincide.
177 */
178 if (sk->sk_bound_dev_if &&
179 sk->sk_bound_dev_if != usin->sin6_scope_id)
180 return -EINVAL;
181
182 sk->sk_bound_dev_if = usin->sin6_scope_id;
183 }
184
185 /* Connect to link-local address requires an interface */
186 if (!sk->sk_bound_dev_if)
187 return -EINVAL;
188 }
189
190 if (tp->rx_opt.ts_recent_stamp &&
191 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
192 tp->rx_opt.ts_recent = 0;
193 tp->rx_opt.ts_recent_stamp = 0;
194 tp->write_seq = 0;
195 }
196
197 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
198 np->flow_label = fl.fl6_flowlabel;
199
200 /*
201 * TCP over IPv4
202 */
203
204 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800205 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 struct sockaddr_in sin;
207
208 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
209
210 if (__ipv6_only_sock(sk))
211 return -ENETUNREACH;
212
213 sin.sin_family = AF_INET;
214 sin.sin_port = usin->sin6_port;
215 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
216
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800217 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800219#ifdef CONFIG_TCP_MD5SIG
220 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
221#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
224
225 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800226 icsk->icsk_ext_hdr_len = exthdrlen;
227 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800229#ifdef CONFIG_TCP_MD5SIG
230 tp->af_specific = &tcp_sock_ipv6_specific;
231#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 goto failure;
233 } else {
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000234 ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
235 ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
236 &np->rcv_saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
238
239 return err;
240 }
241
242 if (!ipv6_addr_any(&np->rcv_saddr))
243 saddr = &np->rcv_saddr;
244
245 fl.proto = IPPROTO_TCP;
246 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
247 ipv6_addr_copy(&fl.fl6_src,
248 (saddr ? saddr : &np->saddr));
249 fl.oif = sk->sk_bound_dev_if;
Brian Haley51953d52009-10-05 08:24:16 +0000250 fl.mark = sk->sk_mark;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 fl.fl_ip_dport = usin->sin6_port;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000252 fl.fl_ip_sport = inet->inet_sport;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000254 final_p = fl6_update_dst(&fl, np->opt, &final);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700256 security_sk_classify_flow(sk, &fl);
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 err = ip6_dst_lookup(sk, &dst, &fl);
259 if (err)
260 goto failure;
261 if (final_p)
262 ipv6_addr_copy(&fl.fl6_dst, final_p);
263
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800264 err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
265 if (err < 0) {
David S. Miller14e50e52007-05-24 18:17:54 -0700266 if (err == -EREMOTE)
267 err = ip6_dst_blackhole(sk, &dst, &fl);
268 if (err < 0)
269 goto failure;
270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272 if (saddr == NULL) {
273 saddr = &fl.fl6_src;
274 ipv6_addr_copy(&np->rcv_saddr, saddr);
275 }
276
277 /* set the source address */
278 ipv6_addr_copy(&np->saddr, saddr);
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000279 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700281 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700282 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
David S. Miller493f3772010-12-02 12:14:29 -0800284 rt = (struct rt6_info *) dst;
285 if (tcp_death_row.sysctl_tw_recycle &&
286 !tp->rx_opt.ts_recent_stamp &&
287 ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) {
288 struct inet_peer *peer = rt6_get_peer(rt);
289 /*
290 * VJ's idea. We save last timestamp seen from
291 * the destination in peer table, when entering state
292 * TIME-WAIT * and initialize rx_opt.ts_recent from it,
293 * when trying new connection.
294 */
295 if (peer) {
296 inet_peer_refcheck(peer);
297 if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
298 tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
299 tp->rx_opt.ts_recent = peer->tcp_ts;
300 }
301 }
302 }
303
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800304 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800306 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
307 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
310
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000311 inet->inet_dport = usin->sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800314 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (err)
316 goto late_failure;
317
318 if (!tp->write_seq)
319 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
320 np->daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000321 inet->inet_sport,
322 inet->inet_dport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 err = tcp_connect(sk);
325 if (err)
326 goto late_failure;
327
328 return 0;
329
330late_failure:
331 tcp_set_state(sk, TCP_CLOSE);
332 __sk_dst_reset(sk);
333failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000334 inet->inet_dport = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 sk->sk_route_caps = 0;
336 return err;
337}
338
339static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700340 u8 type, u8 code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300343 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 struct ipv6_pinfo *np;
345 struct sock *sk;
346 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900347 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 __u32 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700349 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700351 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800352 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700355 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
356 ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return;
358 }
359
360 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700361 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 return;
363 }
364
365 bh_lock_sock(sk);
366 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700367 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 if (sk->sk_state == TCP_CLOSE)
370 goto out;
371
Stephen Hemmingere802af92010-04-22 15:24:53 -0700372 if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
373 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
374 goto out;
375 }
376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900378 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (sk->sk_state != TCP_LISTEN &&
380 !between(seq, tp->snd_una, tp->snd_nxt)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700381 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 goto out;
383 }
384
385 np = inet6_sk(sk);
386
387 if (type == ICMPV6_PKT_TOOBIG) {
388 struct dst_entry *dst = NULL;
389
390 if (sock_owned_by_user(sk))
391 goto out;
392 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
393 goto out;
394
395 /* icmp should have updated the destination cache entry */
396 dst = __sk_dst_check(sk, np->dst_cookie);
397
398 if (dst == NULL) {
399 struct inet_sock *inet = inet_sk(sk);
400 struct flowi fl;
401
402 /* BUGGG_FUTURE: Again, it is not clear how
403 to handle rthdr case. Ignore this complexity
404 for now.
405 */
406 memset(&fl, 0, sizeof(fl));
407 fl.proto = IPPROTO_TCP;
408 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
409 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
410 fl.oif = sk->sk_bound_dev_if;
Brian Haley51953d52009-10-05 08:24:16 +0000411 fl.mark = sk->sk_mark;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000412 fl.fl_ip_dport = inet->inet_dport;
413 fl.fl_ip_sport = inet->inet_sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700414 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
417 sk->sk_err_soft = -err;
418 goto out;
419 }
420
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800421 if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 sk->sk_err_soft = -err;
423 goto out;
424 }
425
426 } else
427 dst_hold(dst);
428
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800429 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 tcp_sync_mss(sk, dst_mtu(dst));
431 tcp_simple_retransmit(sk);
432 } /* else let the usual retransmit timer handle it */
433 dst_release(dst);
434 goto out;
435 }
436
437 icmpv6_err_convert(type, code, &err);
438
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700439 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700441 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 case TCP_LISTEN:
443 if (sock_owned_by_user(sk))
444 goto out;
445
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800446 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
447 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (!req)
449 goto out;
450
451 /* ICMPs are not backlogged, hence we cannot get
452 * an established socket here.
453 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700454 WARN_ON(req->sk != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700456 if (seq != tcp_rsk(req)->snt_isn) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700457 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 goto out;
459 }
460
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700461 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 goto out;
463
464 case TCP_SYN_SENT:
465 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900466 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 sk->sk_err = err;
469 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
470
471 tcp_done(sk);
472 } else
473 sk->sk_err_soft = err;
474 goto out;
475 }
476
477 if (!sock_owned_by_user(sk) && np->recverr) {
478 sk->sk_err = err;
479 sk->sk_error_report(sk);
480 } else
481 sk->sk_err_soft = err;
482
483out:
484 bh_unlock_sock(sk);
485 sock_put(sk);
486}
487
488
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000489static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
490 struct request_values *rvp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800492 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 struct ipv6_pinfo *np = inet6_sk(sk);
494 struct sk_buff * skb;
495 struct ipv6_txoptions *opt = NULL;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000496 struct in6_addr * final_p, final;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 struct flowi fl;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800498 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 int err = -1;
500
501 memset(&fl, 0, sizeof(fl));
502 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700503 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
504 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700506 fl.oif = treq->iif;
Brian Haley51953d52009-10-05 08:24:16 +0000507 fl.mark = sk->sk_mark;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700508 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
KOVACS Krisztianfd507032008-10-19 23:35:58 -0700509 fl.fl_ip_sport = inet_rsk(req)->loc_port;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700510 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800512 opt = np->opt;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000513 final_p = fl6_update_dst(&fl, opt, &final);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800515 err = ip6_dst_lookup(sk, &dst, &fl);
516 if (err)
517 goto done;
518 if (final_p)
519 ipv6_addr_copy(&fl.fl6_dst, final_p);
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800520 if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800521 goto done;
522
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000523 skb = tcp_make_synack(sk, dst, req, rvp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (skb) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000525 __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700527 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Shan Wei4e15ed42010-04-15 16:43:08 +0000528 err = ip6_xmit(sk, skb, &fl, opt);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200529 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 }
531
532done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900533 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800535 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 return err;
537}
538
Octavian Purdila72659ec2010-01-17 19:09:39 -0800539static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
540 struct request_values *rvp)
541{
542 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
543 return tcp_v6_send_synack(sk, req, rvp);
544}
545
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800546static inline void syn_flood_warning(struct sk_buff *skb)
547{
548#ifdef CONFIG_SYN_COOKIES
549 if (sysctl_tcp_syncookies)
550 printk(KERN_INFO
551 "TCPv6: Possible SYN flooding on port %d. "
552 "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
553 else
554#endif
555 printk(KERN_INFO
556 "TCPv6: Possible SYN flooding on port %d. "
557 "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
558}
559
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700560static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
Wei Yongjun800d55f2009-02-23 21:45:33 +0000562 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}
564
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800565#ifdef CONFIG_TCP_MD5SIG
566static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
567 struct in6_addr *addr)
568{
569 struct tcp_sock *tp = tcp_sk(sk);
570 int i;
571
572 BUG_ON(tp == NULL);
573
574 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
575 return NULL;
576
577 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900578 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
David S. Millerf8ab18d2007-09-28 15:18:35 -0700579 return &tp->md5sig_info->keys6[i].base;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800580 }
581 return NULL;
582}
583
584static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
585 struct sock *addr_sk)
586{
587 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
588}
589
590static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
591 struct request_sock *req)
592{
593 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
594}
595
596static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
597 char *newkey, u8 newkeylen)
598{
599 /* Add key to the list */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700600 struct tcp_md5sig_key *key;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800601 struct tcp_sock *tp = tcp_sk(sk);
602 struct tcp6_md5sig_key *keys;
603
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700604 key = tcp_v6_md5_do_lookup(sk, peer);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800605 if (key) {
606 /* modify existing entry - just update that one */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700607 kfree(key->key);
608 key->key = newkey;
609 key->keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800610 } else {
611 /* reallocate new list if current one is full. */
612 if (!tp->md5sig_info) {
613 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
614 if (!tp->md5sig_info) {
615 kfree(newkey);
616 return -ENOMEM;
617 }
Eric Dumazeta4654192010-05-16 00:36:33 -0700618 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800619 }
Wu Fengguangaa133072009-09-02 23:45:45 -0700620 if (tcp_alloc_md5sig_pool(sk) == NULL) {
YOSHIFUJI Hideakiaacbe8c2007-11-20 17:30:56 -0800621 kfree(newkey);
622 return -ENOMEM;
623 }
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800624 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
625 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
626 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
627
628 if (!keys) {
629 tcp_free_md5sig_pool();
630 kfree(newkey);
631 return -ENOMEM;
632 }
633
634 if (tp->md5sig_info->entries6)
635 memmove(keys, tp->md5sig_info->keys6,
636 (sizeof (tp->md5sig_info->keys6[0]) *
637 tp->md5sig_info->entries6));
638
639 kfree(tp->md5sig_info->keys6);
640 tp->md5sig_info->keys6 = keys;
641 tp->md5sig_info->alloced6++;
642 }
643
644 ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
645 peer);
David S. Millerf8ab18d2007-09-28 15:18:35 -0700646 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
647 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800648
649 tp->md5sig_info->entries6++;
650 }
651 return 0;
652}
653
654static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
655 u8 *newkey, __u8 newkeylen)
656{
657 return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr,
658 newkey, newkeylen);
659}
660
661static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
662{
663 struct tcp_sock *tp = tcp_sk(sk);
664 int i;
665
666 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900667 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800668 /* Free the key */
David S. Millerf8ab18d2007-09-28 15:18:35 -0700669 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800670 tp->md5sig_info->entries6--;
671
672 if (tp->md5sig_info->entries6 == 0) {
673 kfree(tp->md5sig_info->keys6);
674 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700675 tp->md5sig_info->alloced6 = 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800676 } else {
677 /* shrink the database */
678 if (tp->md5sig_info->entries6 != i)
679 memmove(&tp->md5sig_info->keys6[i],
680 &tp->md5sig_info->keys6[i+1],
681 (tp->md5sig_info->entries6 - i)
682 * sizeof (tp->md5sig_info->keys6[0]));
683 }
YOSHIFUJI Hideaki77adefd2007-11-20 17:31:23 -0800684 tcp_free_md5sig_pool();
685 return 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800686 }
687 }
688 return -ENOENT;
689}
690
691static void tcp_v6_clear_md5_list (struct sock *sk)
692{
693 struct tcp_sock *tp = tcp_sk(sk);
694 int i;
695
696 if (tp->md5sig_info->entries6) {
697 for (i = 0; i < tp->md5sig_info->entries6; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700698 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800699 tp->md5sig_info->entries6 = 0;
700 tcp_free_md5sig_pool();
701 }
702
703 kfree(tp->md5sig_info->keys6);
704 tp->md5sig_info->keys6 = NULL;
705 tp->md5sig_info->alloced6 = 0;
706
707 if (tp->md5sig_info->entries4) {
708 for (i = 0; i < tp->md5sig_info->entries4; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700709 kfree(tp->md5sig_info->keys4[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800710 tp->md5sig_info->entries4 = 0;
711 tcp_free_md5sig_pool();
712 }
713
714 kfree(tp->md5sig_info->keys4);
715 tp->md5sig_info->keys4 = NULL;
716 tp->md5sig_info->alloced4 = 0;
717}
718
719static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
720 int optlen)
721{
722 struct tcp_md5sig cmd;
723 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
724 u8 *newkey;
725
726 if (optlen < sizeof(cmd))
727 return -EINVAL;
728
729 if (copy_from_user(&cmd, optval, sizeof(cmd)))
730 return -EFAULT;
731
732 if (sin6->sin6_family != AF_INET6)
733 return -EINVAL;
734
735 if (!cmd.tcpm_keylen) {
736 if (!tcp_sk(sk)->md5sig_info)
737 return -ENOENT;
Brian Haleye773e4f2007-08-24 23:16:08 -0700738 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800739 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
740 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
741 }
742
743 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
744 return -EINVAL;
745
746 if (!tcp_sk(sk)->md5sig_info) {
747 struct tcp_sock *tp = tcp_sk(sk);
748 struct tcp_md5sig_info *p;
749
750 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
751 if (!p)
752 return -ENOMEM;
753
754 tp->md5sig_info = p;
Eric Dumazeta4654192010-05-16 00:36:33 -0700755 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800756 }
757
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200758 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800759 if (!newkey)
760 return -ENOMEM;
Brian Haleye773e4f2007-08-24 23:16:08 -0700761 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800762 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
763 newkey, cmd.tcpm_keylen);
764 }
765 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
766}
767
Adam Langley49a72df2008-07-19 00:01:42 -0700768static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
769 struct in6_addr *daddr,
770 struct in6_addr *saddr, int nbytes)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800771{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800772 struct tcp6_pseudohdr *bp;
Adam Langley49a72df2008-07-19 00:01:42 -0700773 struct scatterlist sg;
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900774
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800775 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800776 /* 1. TCP pseudo-header (RFC2460) */
777 ipv6_addr_copy(&bp->saddr, saddr);
778 ipv6_addr_copy(&bp->daddr, daddr);
Adam Langley49a72df2008-07-19 00:01:42 -0700779 bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley00b13042008-07-31 21:36:07 -0700780 bp->len = cpu_to_be32(nbytes);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800781
Adam Langley49a72df2008-07-19 00:01:42 -0700782 sg_init_one(&sg, bp, sizeof(*bp));
783 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
784}
David S. Millerc7da57a2007-10-26 00:41:21 -0700785
Adam Langley49a72df2008-07-19 00:01:42 -0700786static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
787 struct in6_addr *daddr, struct in6_addr *saddr,
788 struct tcphdr *th)
789{
790 struct tcp_md5sig_pool *hp;
791 struct hash_desc *desc;
792
793 hp = tcp_get_md5sig_pool();
794 if (!hp)
795 goto clear_hash_noput;
796 desc = &hp->md5_desc;
797
798 if (crypto_hash_init(desc))
799 goto clear_hash;
800 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
801 goto clear_hash;
802 if (tcp_md5_hash_header(hp, th))
803 goto clear_hash;
804 if (tcp_md5_hash_key(hp, key))
805 goto clear_hash;
806 if (crypto_hash_final(desc, md5_hash))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800807 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800808
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800809 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800810 return 0;
Adam Langley49a72df2008-07-19 00:01:42 -0700811
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800812clear_hash:
813 tcp_put_md5sig_pool();
814clear_hash_noput:
815 memset(md5_hash, 0, 16);
Adam Langley49a72df2008-07-19 00:01:42 -0700816 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800817}
818
Adam Langley49a72df2008-07-19 00:01:42 -0700819static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
820 struct sock *sk, struct request_sock *req,
821 struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800822{
823 struct in6_addr *saddr, *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700824 struct tcp_md5sig_pool *hp;
825 struct hash_desc *desc;
826 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800827
828 if (sk) {
829 saddr = &inet6_sk(sk)->saddr;
830 daddr = &inet6_sk(sk)->daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700831 } else if (req) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800832 saddr = &inet6_rsk(req)->loc_addr;
833 daddr = &inet6_rsk(req)->rmt_addr;
Adam Langley49a72df2008-07-19 00:01:42 -0700834 } else {
835 struct ipv6hdr *ip6h = ipv6_hdr(skb);
836 saddr = &ip6h->saddr;
837 daddr = &ip6h->daddr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800838 }
Adam Langley49a72df2008-07-19 00:01:42 -0700839
840 hp = tcp_get_md5sig_pool();
841 if (!hp)
842 goto clear_hash_noput;
843 desc = &hp->md5_desc;
844
845 if (crypto_hash_init(desc))
846 goto clear_hash;
847
848 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
849 goto clear_hash;
850 if (tcp_md5_hash_header(hp, th))
851 goto clear_hash;
852 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
853 goto clear_hash;
854 if (tcp_md5_hash_key(hp, key))
855 goto clear_hash;
856 if (crypto_hash_final(desc, md5_hash))
857 goto clear_hash;
858
859 tcp_put_md5sig_pool();
860 return 0;
861
862clear_hash:
863 tcp_put_md5sig_pool();
864clear_hash_noput:
865 memset(md5_hash, 0, 16);
866 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800867}
868
869static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
870{
871 __u8 *hash_location = NULL;
872 struct tcp_md5sig_key *hash_expected;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700873 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700874 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800875 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800876 u8 newhash[16];
877
878 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900879 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800880
David S. Miller785957d2008-07-30 03:03:15 -0700881 /* We've parsed the options - do we have a hash? */
882 if (!hash_expected && !hash_location)
883 return 0;
884
885 if (hash_expected && !hash_location) {
886 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800887 return 1;
888 }
889
David S. Miller785957d2008-07-30 03:03:15 -0700890 if (!hash_expected && hash_location) {
891 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800892 return 1;
893 }
894
895 /* check the signature */
Adam Langley49a72df2008-07-19 00:01:42 -0700896 genhash = tcp_v6_md5_hash_skb(newhash,
897 hash_expected,
898 NULL, NULL, skb);
899
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800900 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
901 if (net_ratelimit()) {
Joe Perches5856b602010-01-08 00:59:52 -0800902 printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800903 genhash ? "failed" : "mismatch",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700904 &ip6h->saddr, ntohs(th->source),
905 &ip6h->daddr, ntohs(th->dest));
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800906 }
907 return 1;
908 }
909 return 0;
910}
911#endif
912
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800913struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700915 .obj_size = sizeof(struct tcp6_request_sock),
Octavian Purdila72659ec2010-01-17 19:09:39 -0800916 .rtx_syn_ack = tcp_v6_rtx_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700917 .send_ack = tcp_v6_reqsk_send_ack,
918 .destructor = tcp_v6_reqsk_destructor,
Octavian Purdila72659ec2010-01-17 19:09:39 -0800919 .send_reset = tcp_v6_send_reset,
920 .syn_ack_timeout = tcp_syn_ack_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921};
922
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800923#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +0000924static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800925 .md5_lookup = tcp_v6_reqsk_md5_lookup,
John Dykstrae3afe7b2009-07-16 05:04:51 +0000926 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800927};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800928#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800929
Herbert Xu8ad50d92010-04-11 02:15:54 +0000930static void __tcp_v6_send_check(struct sk_buff *skb,
931 struct in6_addr *saddr, struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700933 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Patrick McHardy84fa7932006-08-29 16:44:56 -0700935 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000936 th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700937 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800938 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 } else {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000940 th->check = tcp_v6_check(skb->len, saddr, daddr,
941 csum_partial(th, th->doff << 2,
942 skb->csum));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944}
945
Herbert Xubb296242010-04-11 02:15:55 +0000946static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Herbert Xu8ad50d92010-04-11 02:15:54 +0000947{
948 struct ipv6_pinfo *np = inet6_sk(sk);
949
950 __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
951}
952
Herbert Xua430a432006-07-08 13:34:56 -0700953static int tcp_v6_gso_send_check(struct sk_buff *skb)
954{
955 struct ipv6hdr *ipv6h;
956 struct tcphdr *th;
957
958 if (!pskb_may_pull(skb, sizeof(*th)))
959 return -EINVAL;
960
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700961 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700962 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700963
964 th->check = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -0700965 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xu8ad50d92010-04-11 02:15:54 +0000966 __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
Herbert Xua430a432006-07-08 13:34:56 -0700967 return 0;
968}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Herbert Xu36990672009-05-22 00:45:28 -0700970static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
971 struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800972{
Herbert Xu36e7b1b2009-04-27 05:44:45 -0700973 struct ipv6hdr *iph = skb_gro_network_header(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800974
975 switch (skb->ip_summed) {
976 case CHECKSUM_COMPLETE:
Herbert Xu86911732009-01-29 14:19:50 +0000977 if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
Herbert Xu684f2172009-01-08 10:41:23 -0800978 skb->csum)) {
979 skb->ip_summed = CHECKSUM_UNNECESSARY;
980 break;
981 }
982
983 /* fall through */
984 case CHECKSUM_NONE:
985 NAPI_GRO_CB(skb)->flush = 1;
986 return NULL;
987 }
988
989 return tcp_gro_receive(head, skb);
990}
Herbert Xu684f2172009-01-08 10:41:23 -0800991
Herbert Xu36990672009-05-22 00:45:28 -0700992static int tcp6_gro_complete(struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800993{
994 struct ipv6hdr *iph = ipv6_hdr(skb);
995 struct tcphdr *th = tcp_hdr(skb);
996
997 th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
998 &iph->saddr, &iph->daddr, 0);
999 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
1000
1001 return tcp_gro_complete(skb);
1002}
Herbert Xu684f2172009-01-08 10:41:23 -08001003
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001004static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
1005 u32 ts, struct tcp_md5sig_key *key, int rst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001007 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 struct sk_buff *buff;
1009 struct flowi fl;
Eric Dumazetadf30902009-06-02 05:19:30 +00001010 struct net *net = dev_net(skb_dst(skb)->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001011 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -08001012 unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazetadf30902009-06-02 05:19:30 +00001013 struct dst_entry *dst;
Al Viroe69a4ad2006-11-14 20:56:00 -08001014 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -07001017 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001018#ifdef CONFIG_TCP_MD5SIG
1019 if (key)
1020 tot_len += TCPOLEN_MD5SIG_ALIGNED;
1021#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
1024 GFP_ATOMIC);
1025 if (buff == NULL)
1026 return;
1027
1028 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
1029
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001030 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Herbert Xu6651ffc2010-04-21 00:47:15 -07001031 skb_reset_transport_header(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 /* Swap the send and the receive. */
1034 memset(t1, 0, sizeof(*t1));
1035 t1->dest = th->source;
1036 t1->source = th->dest;
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001037 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 t1->seq = htonl(seq);
1039 t1->ack_seq = htonl(ack);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001040 t1->ack = !rst || !th->ack;
1041 t1->rst = rst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001043
Al Viroe69a4ad2006-11-14 20:56:00 -08001044 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001047 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1048 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
1049 *topt++ = htonl(tcp_time_stamp);
Ilpo Järvinen53b12572008-10-08 14:36:33 -07001050 *topt++ = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
1052
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001053#ifdef CONFIG_TCP_MD5SIG
1054 if (key) {
1055 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1056 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Adam Langley49a72df2008-07-19 00:01:42 -07001057 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
Adam Langley90b7e112008-07-31 20:49:48 -07001058 &ipv6_hdr(skb)->saddr,
1059 &ipv6_hdr(skb)->daddr, t1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001060 }
1061#endif
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001064 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1065 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
David S. Millere5700af2010-04-21 14:59:20 -07001067 buff->ip_summed = CHECKSUM_PARTIAL;
1068 buff->csum = 0;
1069
Herbert Xu8ad50d92010-04-11 02:15:54 +00001070 __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001073 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 fl.fl_ip_dport = t1->dest;
1075 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001076 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001078 /* Pass a socket to ip6_dst_lookup either it is for RST
1079 * Underlying function will use this to retrieve the network
1080 * namespace
1081 */
Eric Dumazetadf30902009-06-02 05:19:30 +00001082 if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
1083 if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
1084 skb_dst_set(buff, dst);
Shan Wei4e15ed42010-04-15 16:43:08 +00001085 ip6_xmit(ctl_sk, buff, &fl, NULL);
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001086 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001087 if (rst)
1088 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092
1093 kfree_skb(buff);
1094}
1095
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001096static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
1097{
1098 struct tcphdr *th = tcp_hdr(skb);
1099 u32 seq = 0, ack_seq = 0;
Guo-Fu Tsengfa3e5b42008-10-09 21:11:56 -07001100 struct tcp_md5sig_key *key = NULL;
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001101
1102 if (th->rst)
1103 return;
1104
1105 if (!ipv6_unicast_destination(skb))
1106 return;
1107
1108#ifdef CONFIG_TCP_MD5SIG
1109 if (sk)
1110 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001111#endif
1112
1113 if (th->ack)
1114 seq = ntohl(th->ack_seq);
1115 else
1116 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
1117 (th->doff << 2);
1118
1119 tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1);
1120}
1121
1122static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
1123 struct tcp_md5sig_key *key)
1124{
1125 tcp_v6_send_response(skb, seq, ack, win, ts, key, 0);
1126}
1127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1129{
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001130 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001131 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001133 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001134 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001135 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001137 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138}
1139
Gui Jianfeng6edafaa2008-08-06 23:50:04 -07001140static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
1141 struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001143 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 -07001144 tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145}
1146
1147
1148static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1149{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001150 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001151 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 struct sock *nsk;
1153
1154 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001155 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001156 &ipv6_hdr(skb)->saddr,
1157 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (req)
1159 return tcp_check_req(sk, skb, req, prev);
1160
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001161 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001162 &ipv6_hdr(skb)->saddr, th->source,
1163 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
1165 if (nsk) {
1166 if (nsk->sk_state != TCP_TIME_WAIT) {
1167 bh_lock_sock(nsk);
1168 return nsk;
1169 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001170 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return NULL;
1172 }
1173
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001174#ifdef CONFIG_SYN_COOKIES
Florian Westphalaf9b4732010-06-03 00:43:44 +00001175 if (!th->syn)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001176 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177#endif
1178 return sk;
1179}
1180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181/* FIXME: this is substantially similar to the ipv4 code.
1182 * Can some kind of merge be done? -- erics
1183 */
1184static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1185{
William Allen Simpson4957faa2009-12-02 18:25:27 +00001186 struct tcp_extend_values tmp_ext;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001187 struct tcp_options_received tmp_opt;
William Allen Simpson4957faa2009-12-02 18:25:27 +00001188 u8 *hash_location;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001189 struct request_sock *req;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001190 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 struct ipv6_pinfo *np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 struct tcp_sock *tp = tcp_sk(sk);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001193 __u32 isn = TCP_SKB_CB(skb)->when;
David S. Miller493f3772010-12-02 12:14:29 -08001194 struct dst_entry *dst = NULL;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001195#ifdef CONFIG_SYN_COOKIES
1196 int want_cookie = 0;
1197#else
1198#define want_cookie 0
1199#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 if (skb->protocol == htons(ETH_P_IP))
1202 return tcp_v4_conn_request(sk, skb);
1203
1204 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001205 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001207 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (net_ratelimit())
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001209 syn_flood_warning(skb);
1210#ifdef CONFIG_SYN_COOKIES
1211 if (sysctl_tcp_syncookies)
1212 want_cookie = 1;
1213 else
1214#endif
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001215 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001218 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 goto drop;
1220
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001221 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 if (req == NULL)
1223 goto drop;
1224
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001225#ifdef CONFIG_TCP_MD5SIG
1226 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1227#endif
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 tcp_clear_options(&tmp_opt);
1230 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1231 tmp_opt.user_mss = tp->rx_opt.user_mss;
David S. Millerbb5b7c12009-12-15 20:56:42 -08001232 tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
William Allen Simpson4957faa2009-12-02 18:25:27 +00001234 if (tmp_opt.cookie_plus > 0 &&
1235 tmp_opt.saw_tstamp &&
1236 !tp->rx_opt.cookie_out_never &&
1237 (sysctl_tcp_cookie_size > 0 ||
1238 (tp->cookie_values != NULL &&
1239 tp->cookie_values->cookie_desired > 0))) {
1240 u8 *c;
1241 u32 *d;
1242 u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
1243 int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
1244
1245 if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
1246 goto drop_and_free;
1247
1248 /* Secret recipe starts with IP addresses */
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001249 d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
William Allen Simpson4957faa2009-12-02 18:25:27 +00001250 *mess++ ^= *d++;
1251 *mess++ ^= *d++;
1252 *mess++ ^= *d++;
1253 *mess++ ^= *d++;
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001254 d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
William Allen Simpson4957faa2009-12-02 18:25:27 +00001255 *mess++ ^= *d++;
1256 *mess++ ^= *d++;
1257 *mess++ ^= *d++;
1258 *mess++ ^= *d++;
1259
1260 /* plus variable length Initiator Cookie */
1261 c = (u8 *)mess;
1262 while (l-- > 0)
1263 *c++ ^= *hash_location++;
1264
1265#ifdef CONFIG_SYN_COOKIES
1266 want_cookie = 0; /* not our kind of cookie */
1267#endif
1268 tmp_ext.cookie_out_never = 0; /* false */
1269 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1270 } else if (!tp->rx_opt.cookie_in_always) {
1271 /* redundant indications, but ensure initialization. */
1272 tmp_ext.cookie_out_never = 1; /* true */
1273 tmp_ext.cookie_plus = 0;
1274 } else {
1275 goto drop_and_free;
1276 }
1277 tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
Florian Westphal4dfc2812008-04-10 03:12:40 -07001279 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001280 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1283 tcp_openreq_init(req, &tmp_opt, skb);
1284
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001285 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001286 ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
1287 ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
Florian Westphal172d69e2010-06-21 11:48:45 +00001288 if (!want_cookie || tmp_opt.tstamp_ok)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001289 TCP_ECN_create_request(req, tcp_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Florian Westphal2bbdf382010-06-13 11:29:39 +00001291 if (!isn) {
David S. Miller493f3772010-12-02 12:14:29 -08001292 struct inet_peer *peer = NULL;
1293
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001294 if (ipv6_opt_accepted(sk, skb) ||
1295 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1296 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1297 atomic_inc(&skb->users);
1298 treq->pktopts = skb;
1299 }
1300 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001302 /* So that link locals have meaning */
1303 if (!sk->sk_bound_dev_if &&
1304 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1305 treq->iif = inet6_iif(skb);
David S. Miller493f3772010-12-02 12:14:29 -08001306
1307 if (want_cookie) {
Florian Westphal2bbdf382010-06-13 11:29:39 +00001308 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
1309 req->cookie_ts = tmp_opt.tstamp_ok;
David S. Miller493f3772010-12-02 12:14:29 -08001310 goto have_isn;
Florian Westphal2bbdf382010-06-13 11:29:39 +00001311 }
David S. Miller493f3772010-12-02 12:14:29 -08001312
1313 /* VJ's idea. We save last timestamp seen
1314 * from the destination in peer table, when entering
1315 * state TIME-WAIT, and check against it before
1316 * accepting new connection request.
1317 *
1318 * If "isn" is not zero, this request hit alive
1319 * timewait bucket, so that all the necessary checks
1320 * are made in the function processing timewait state.
1321 */
1322 if (tmp_opt.saw_tstamp &&
1323 tcp_death_row.sysctl_tw_recycle &&
1324 (dst = inet6_csk_route_req(sk, req)) != NULL &&
1325 (peer = rt6_get_peer((struct rt6_info *)dst)) != NULL &&
David S. Miller7a71ed82011-02-09 14:30:26 -08001326 ipv6_addr_equal((struct in6_addr *)peer->daddr.addr.a6,
David S. Miller493f3772010-12-02 12:14:29 -08001327 &treq->rmt_addr)) {
1328 inet_peer_refcheck(peer);
1329 if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
1330 (s32)(peer->tcp_ts - req->ts_recent) >
1331 TCP_PAWS_WINDOW) {
1332 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
1333 goto drop_and_release;
1334 }
1335 }
1336 /* Kill the following clause, if you dislike this way. */
1337 else if (!sysctl_tcp_syncookies &&
1338 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
1339 (sysctl_max_syn_backlog >> 2)) &&
1340 (!peer || !peer->tcp_ts_stamp) &&
1341 (!dst || !dst_metric(dst, RTAX_RTT))) {
1342 /* Without syncookies last quarter of
1343 * backlog is filled with destinations,
1344 * proven to be alive.
1345 * It means that we continue to communicate
1346 * to destinations, already remembered
1347 * to the moment of synflood.
1348 */
1349 LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n",
1350 &treq->rmt_addr, ntohs(tcp_hdr(skb)->source));
1351 goto drop_and_release;
1352 }
1353
1354 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001355 }
David S. Miller493f3772010-12-02 12:14:29 -08001356have_isn:
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001357 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001359 security_inet_conn_request(sk, skb, req);
1360
William Allen Simpson4957faa2009-12-02 18:25:27 +00001361 if (tcp_v6_send_synack(sk, req,
1362 (struct request_values *)&tmp_ext) ||
1363 want_cookie)
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001364 goto drop_and_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001366 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1367 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
David S. Miller493f3772010-12-02 12:14:29 -08001369drop_and_release:
1370 dst_release(dst);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001371drop_and_free:
1372 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373drop:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 return 0; /* don't send reset */
1375}
1376
1377static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001378 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 struct dst_entry *dst)
1380{
Vegard Nossum78d15e82008-09-12 16:17:43 -07001381 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1383 struct tcp6_sock *newtcp6sk;
1384 struct inet_sock *newinet;
1385 struct tcp_sock *newtp;
1386 struct sock *newsk;
1387 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001388#ifdef CONFIG_TCP_MD5SIG
1389 struct tcp_md5sig_key *key;
1390#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
1392 if (skb->protocol == htons(ETH_P_IP)) {
1393 /*
1394 * v6 mapped
1395 */
1396
1397 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1398
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001399 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 return NULL;
1401
1402 newtcp6sk = (struct tcp6_sock *)newsk;
1403 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1404
1405 newinet = inet_sk(newsk);
1406 newnp = inet6_sk(newsk);
1407 newtp = tcp_sk(newsk);
1408
1409 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1410
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001411 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001413 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
1415 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1416
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001417 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001419#ifdef CONFIG_TCP_MD5SIG
1420 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1421#endif
1422
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 newnp->pktoptions = NULL;
1424 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001425 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001426 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001428 /*
1429 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1430 * here, tcp_create_openreq_child now does this for us, see the comment in
1431 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
1434 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001435 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 Sync it now.
1437 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001438 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440 return newsk;
1441 }
1442
Vegard Nossum78d15e82008-09-12 16:17:43 -07001443 treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 opt = np->opt;
1445
1446 if (sk_acceptq_is_full(sk))
1447 goto out_overflow;
1448
David S. Miller493f3772010-12-02 12:14:29 -08001449 if (!dst) {
1450 dst = inet6_csk_route_req(sk, req);
1451 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001453 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455 newsk = tcp_create_openreq_child(sk, req, skb);
1456 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +02001457 goto out_nonewsk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001459 /*
1460 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1461 * count here, tcp_create_openreq_child now does this for us, see the
1462 * comment in that function for the gory details. -acme
1463 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Stephen Hemminger59eed272006-08-25 15:55:43 -07001465 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001466 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 newtcp6sk = (struct tcp6_sock *)newsk;
1469 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1470
1471 newtp = tcp_sk(newsk);
1472 newinet = inet_sk(newsk);
1473 newnp = inet6_sk(newsk);
1474
1475 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1476
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001477 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1478 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1479 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1480 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001482 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484 First: no IPv4 options.
1485 */
1486 newinet->opt = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001487 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
1489 /* Clone RX bits */
1490 newnp->rxopt.all = np->rxopt.all;
1491
1492 /* Clone pktoptions received with SYN */
1493 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001494 if (treq->pktopts != NULL) {
1495 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1496 kfree_skb(treq->pktopts);
1497 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 if (newnp->pktoptions)
1499 skb_set_owner_r(newnp->pktoptions, newsk);
1500 }
1501 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001502 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001503 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 /* Clone native IPv6 options from listening socket (if any)
1506
1507 Yes, keeping reference count would be much more clever,
1508 but we make one more one thing there: reattach optmem
1509 to newsk.
1510 */
1511 if (opt) {
1512 newnp->opt = ipv6_dup_options(newsk, opt);
1513 if (opt != np->opt)
1514 sock_kfree_s(sk, opt, opt->tot_len);
1515 }
1516
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001517 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001519 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1520 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
John Heffner5d424d52006-03-20 17:53:41 -08001522 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 tcp_sync_mss(newsk, dst_mtu(dst));
David S. Miller0dbaee32010-12-13 12:52:14 -08001524 newtp->advmss = dst_metric_advmss(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 tcp_initialize_rcv_mss(newsk);
1526
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001527 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
1528 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001530#ifdef CONFIG_TCP_MD5SIG
1531 /* Copy over the MD5 key from the original socket */
1532 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1533 /* We're using one, so create a matching key
1534 * on the newsk structure. If we fail to get
1535 * memory, then we end up not copying the key
1536 * across. Shucks.
1537 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001538 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1539 if (newkey != NULL)
John Dykstrae547bc12009-07-17 09:23:22 +00001540 tcp_v6_md5_do_add(newsk, &newnp->daddr,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001541 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001542 }
1543#endif
1544
Balazs Scheidler093d2822010-10-21 13:06:43 +02001545 if (__inet_inherit_port(sk, newsk) < 0) {
1546 sock_put(newsk);
1547 goto out;
1548 }
Eric Dumazet9327f702009-12-04 03:46:54 +00001549 __inet6_hash(newsk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
1551 return newsk;
1552
1553out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001554 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001555out_nonewsk:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 if (opt && opt != np->opt)
1557 sock_kfree_s(sk, opt, opt->tot_len);
1558 dst_release(dst);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001559out:
1560 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 return NULL;
1562}
1563
Al Virob51655b2006-11-14 21:40:42 -08001564static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001566 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Herbert Xu684f2172009-01-08 10:41:23 -08001567 if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001568 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001569 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001573
Herbert Xu684f2172009-01-08 10:41:23 -08001574 skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001575 &ipv6_hdr(skb)->saddr,
1576 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001579 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 }
1581 return 0;
1582}
1583
1584/* The socket must have it's spinlock held when we get
1585 * here.
1586 *
1587 * We have a potential double-lock case here, so even when
1588 * doing backlog processing we use the BH locking scheme.
1589 * This is because we cannot sleep with the original spinlock
1590 * held.
1591 */
1592static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1593{
1594 struct ipv6_pinfo *np = inet6_sk(sk);
1595 struct tcp_sock *tp;
1596 struct sk_buff *opt_skb = NULL;
1597
1598 /* Imagine: socket is IPv6. IPv4 packet arrives,
1599 goes to IPv4 receive handler and backlogged.
1600 From backlog it always goes here. Kerboom...
1601 Fortunately, tcp_rcv_established and rcv_established
1602 handle them correctly, but it is not case with
1603 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1604 */
1605
1606 if (skb->protocol == htons(ETH_P_IP))
1607 return tcp_v4_do_rcv(sk, skb);
1608
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001609#ifdef CONFIG_TCP_MD5SIG
1610 if (tcp_v6_inbound_md5_hash (sk, skb))
1611 goto discard;
1612#endif
1613
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001614 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 goto discard;
1616
1617 /*
1618 * socket locking is here for SMP purposes as backlog rcv
1619 * is currently called with bh processing disabled.
1620 */
1621
1622 /* Do Stevens' IPV6_PKTOPTIONS.
1623
1624 Yes, guys, it is the only place in our code, where we
1625 may make it not affecting IPv4.
1626 The rest of code is protocol independent,
1627 and I do not like idea to uglify IPv4.
1628
1629 Actually, all the idea behind IPV6_PKTOPTIONS
1630 looks not very well thought. For now we latch
1631 options, received in the last packet, enqueued
1632 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001633 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 */
1635 if (np->rxopt.all)
1636 opt_skb = skb_clone(skb, GFP_ATOMIC);
1637
1638 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001639 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 goto reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 if (opt_skb)
1642 goto ipv6_pktoptions;
1643 return 0;
1644 }
1645
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001646 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 goto csum_err;
1648
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001649 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1651 if (!nsk)
1652 goto discard;
1653
1654 /*
1655 * Queue it on the new socket if the new socket is active,
1656 * otherwise we just shortcircuit this and continue with
1657 * the new socket..
1658 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001659 if(nsk != sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 if (tcp_child_process(sk, nsk, skb))
1661 goto reset;
1662 if (opt_skb)
1663 __kfree_skb(opt_skb);
1664 return 0;
1665 }
1666 }
1667
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001668 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 goto reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (opt_skb)
1671 goto ipv6_pktoptions;
1672 return 0;
1673
1674reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001675 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676discard:
1677 if (opt_skb)
1678 __kfree_skb(opt_skb);
1679 kfree_skb(skb);
1680 return 0;
1681csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001682 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 goto discard;
1684
1685
1686ipv6_pktoptions:
1687 /* Do you ask, what is it?
1688
1689 1. skb was enqueued by tcp.
1690 2. skb is added to tail of read queue, rather than out of order.
1691 3. socket is not in passive state.
1692 4. Finally, it really contains options, which user wants to receive.
1693 */
1694 tp = tcp_sk(sk);
1695 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1696 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001697 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001698 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001699 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001700 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (ipv6_opt_accepted(sk, opt_skb)) {
1702 skb_set_owner_r(opt_skb, sk);
1703 opt_skb = xchg(&np->pktoptions, opt_skb);
1704 } else {
1705 __kfree_skb(opt_skb);
1706 opt_skb = xchg(&np->pktoptions, NULL);
1707 }
1708 }
1709
Wei Yongjun800d55f2009-02-23 21:45:33 +00001710 kfree_skb(opt_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 return 0;
1712}
1713
Herbert Xue5bbef22007-10-15 12:50:28 -07001714static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001716 struct tcphdr *th;
Stephen Hemmingere802af92010-04-22 15:24:53 -07001717 struct ipv6hdr *hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 struct sock *sk;
1719 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001720 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
1722 if (skb->pkt_type != PACKET_HOST)
1723 goto discard_it;
1724
1725 /*
1726 * Count it even if it's bad.
1727 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001728 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
1730 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1731 goto discard_it;
1732
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001733 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 if (th->doff < sizeof(struct tcphdr)/4)
1736 goto bad_packet;
1737 if (!pskb_may_pull(skb, th->doff*4))
1738 goto discard_it;
1739
Herbert Xu60476372007-04-09 11:59:39 -07001740 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 goto bad_packet;
1742
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001743 th = tcp_hdr(skb);
Stephen Hemmingere802af92010-04-22 15:24:53 -07001744 hdr = ipv6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1746 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1747 skb->len - th->doff*4);
1748 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1749 TCP_SKB_CB(skb)->when = 0;
Stephen Hemmingere802af92010-04-22 15:24:53 -07001750 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 TCP_SKB_CB(skb)->sacked = 0;
1752
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -07001753 sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 if (!sk)
1755 goto no_tcp_socket;
1756
1757process:
1758 if (sk->sk_state == TCP_TIME_WAIT)
1759 goto do_time_wait;
1760
Stephen Hemmingere802af92010-04-22 15:24:53 -07001761 if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) {
1762 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
1763 goto discard_and_relse;
1764 }
1765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1767 goto discard_and_relse;
1768
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001769 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 goto discard_and_relse;
1771
1772 skb->dev = NULL;
1773
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001774 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 ret = 0;
1776 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001777#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001778 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001779 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
Dan Williamsf67b4592009-01-06 11:38:15 -07001780 tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001781 if (tp->ucopy.dma_chan)
1782 ret = tcp_v6_do_rcv(sk, skb);
1783 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001784#endif
1785 {
1786 if (!tcp_prequeue(sk, skb))
1787 ret = tcp_v6_do_rcv(sk, skb);
1788 }
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001789 } else if (unlikely(sk_add_backlog(sk, skb))) {
Zhu Yi6b03a532010-03-04 18:01:41 +00001790 bh_unlock_sock(sk);
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001791 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
Zhu Yi6b03a532010-03-04 18:01:41 +00001792 goto discard_and_relse;
1793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 bh_unlock_sock(sk);
1795
1796 sock_put(sk);
1797 return ret ? -1 : 0;
1798
1799no_tcp_socket:
1800 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1801 goto discard_it;
1802
1803 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1804bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001805 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001807 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 }
1809
1810discard_it:
1811
1812 /*
1813 * Discard frame
1814 */
1815
1816 kfree_skb(skb);
1817 return 0;
1818
1819discard_and_relse:
1820 sock_put(sk);
1821 goto discard_it;
1822
1823do_time_wait:
1824 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001825 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 goto discard_it;
1827 }
1828
1829 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001830 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001831 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 goto discard_it;
1833 }
1834
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001835 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 case TCP_TW_SYN:
1837 {
1838 struct sock *sk2;
1839
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001840 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001841 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001842 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001844 struct inet_timewait_sock *tw = inet_twsk(sk);
1845 inet_twsk_deschedule(tw, &tcp_death_row);
1846 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 sk = sk2;
1848 goto process;
1849 }
1850 /* Fall through to ACK */
1851 }
1852 case TCP_TW_ACK:
1853 tcp_v6_timewait_ack(sk, skb);
1854 break;
1855 case TCP_TW_RST:
1856 goto no_tcp_socket;
1857 case TCP_TW_SUCCESS:;
1858 }
1859 goto discard_it;
1860}
1861
David S. Millerccb7c412010-12-01 18:09:13 -08001862static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863{
David S. Millerdb3949c2010-12-02 11:52:07 -08001864 struct rt6_info *rt = (struct rt6_info *) __sk_dst_get(sk);
1865 struct ipv6_pinfo *np = inet6_sk(sk);
1866 struct inet_peer *peer;
1867
1868 if (!rt ||
1869 !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr)) {
1870 peer = inet_getpeer_v6(&np->daddr, 1);
1871 *release_it = true;
1872 } else {
1873 if (!rt->rt6i_peer)
1874 rt6_bind_peer(rt, 1);
1875 peer = rt->rt6i_peer;
David S. Miller457de432010-12-10 13:16:09 -08001876 *release_it = false;
David S. Millerdb3949c2010-12-02 11:52:07 -08001877 }
1878
1879 return peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880}
1881
David S. Millerccb7c412010-12-01 18:09:13 -08001882static void *tcp_v6_tw_get_peer(struct sock *sk)
1883{
David S. Millerdb3949c2010-12-02 11:52:07 -08001884 struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
David S. Millerccb7c412010-12-01 18:09:13 -08001885 struct inet_timewait_sock *tw = inet_twsk(sk);
1886
1887 if (tw->tw_family == AF_INET)
1888 return tcp_v4_tw_get_peer(sk);
1889
David S. Millerdb3949c2010-12-02 11:52:07 -08001890 return inet_getpeer_v6(&tw6->tw_v6_daddr, 1);
David S. Millerccb7c412010-12-01 18:09:13 -08001891}
1892
1893static struct timewait_sock_ops tcp6_timewait_sock_ops = {
1894 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
1895 .twsk_unique = tcp_twsk_unique,
1896 .twsk_destructor= tcp_twsk_destructor,
1897 .twsk_getpeer = tcp_v6_tw_get_peer,
1898};
1899
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001900static const struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001901 .queue_xmit = inet6_csk_xmit,
1902 .send_check = tcp_v6_send_check,
1903 .rebuild_header = inet6_sk_rebuild_header,
1904 .conn_request = tcp_v6_conn_request,
1905 .syn_recv_sock = tcp_v6_syn_recv_sock,
David S. Miller3f419d22010-11-29 13:37:14 -08001906 .get_peer = tcp_v6_get_peer,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001907 .net_header_len = sizeof(struct ipv6hdr),
1908 .setsockopt = ipv6_setsockopt,
1909 .getsockopt = ipv6_getsockopt,
1910 .addr2sockaddr = inet6_csk_addr2sockaddr,
1911 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001912 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001913#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001914 .compat_setsockopt = compat_ipv6_setsockopt,
1915 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001916#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917};
1918
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001919#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001920static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001921 .md5_lookup = tcp_v6_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001922 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001923 .md5_add = tcp_v6_md5_add_func,
1924 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001925};
David S. Millera9286302006-11-14 19:53:22 -08001926#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928/*
1929 * TCP over IPv4 via INET6 API
1930 */
1931
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001932static const struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001933 .queue_xmit = ip_queue_xmit,
1934 .send_check = tcp_v4_send_check,
1935 .rebuild_header = inet_sk_rebuild_header,
1936 .conn_request = tcp_v6_conn_request,
1937 .syn_recv_sock = tcp_v6_syn_recv_sock,
David S. Miller3f419d22010-11-29 13:37:14 -08001938 .get_peer = tcp_v4_get_peer,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001939 .net_header_len = sizeof(struct iphdr),
1940 .setsockopt = ipv6_setsockopt,
1941 .getsockopt = ipv6_getsockopt,
1942 .addr2sockaddr = inet6_csk_addr2sockaddr,
1943 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001944 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001945#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001946 .compat_setsockopt = compat_ipv6_setsockopt,
1947 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001948#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949};
1950
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001951#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001952static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001953 .md5_lookup = tcp_v4_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001954 .calc_md5_hash = tcp_v4_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001955 .md5_add = tcp_v6_md5_add_func,
1956 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001957};
David S. Millera9286302006-11-14 19:53:22 -08001958#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001959
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960/* NOTE: A lot of things set to zero explicitly by call to
1961 * sk_alloc() so need not be done here.
1962 */
1963static int tcp_v6_init_sock(struct sock *sk)
1964{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001965 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 struct tcp_sock *tp = tcp_sk(sk);
1967
1968 skb_queue_head_init(&tp->out_of_order_queue);
1969 tcp_init_xmit_timers(sk);
1970 tcp_prequeue_init(tp);
1971
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001972 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 tp->mdev = TCP_TIMEOUT_INIT;
1974
1975 /* So many TCP implementations out there (incorrectly) count the
1976 * initial SYN frame in their delayed-ACK and congestion control
1977 * algorithms that we must have the following bandaid to talk
1978 * efficiently to them. -DaveM
1979 */
1980 tp->snd_cwnd = 2;
1981
1982 /* See draft-stevens-tcpca-spec-01 for discussion of the
1983 * initialization of these values.
1984 */
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07001985 tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 tp->snd_cwnd_clamp = ~0;
William Allen Simpsonbee7ca92009-11-10 09:51:18 +00001987 tp->mss_cache = TCP_MSS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
1989 tp->reordering = sysctl_tcp_reordering;
1990
1991 sk->sk_state = TCP_CLOSE;
1992
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001993 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001994 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001995 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 sk->sk_write_space = sk_stream_write_space;
1997 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1998
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001999#ifdef CONFIG_TCP_MD5SIG
2000 tp->af_specific = &tcp_sock_ipv6_specific;
2001#endif
2002
William Allen Simpson435cf552009-12-02 18:17:05 +00002003 /* TCP Cookie Transactions */
2004 if (sysctl_tcp_cookie_size > 0) {
2005 /* Default, cookies without s_data_payload. */
2006 tp->cookie_values =
2007 kzalloc(sizeof(*tp->cookie_values),
2008 sk->sk_allocation);
2009 if (tp->cookie_values != NULL)
2010 kref_init(&tp->cookie_values->kref);
2011 }
2012 /* Presumed zeroed, in order of appearance:
2013 * cookie_in_always, cookie_out_never,
2014 * s_data_constant, s_data_in, s_data_out
2015 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 sk->sk_sndbuf = sysctl_tcp_wmem[1];
2017 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
2018
Herbert Xueb4dea52008-12-29 23:04:08 -08002019 local_bh_disable();
Eric Dumazet17483762008-11-25 21:16:35 -08002020 percpu_counter_inc(&tcp_sockets_allocated);
Herbert Xueb4dea52008-12-29 23:04:08 -08002021 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023 return 0;
2024}
2025
Brian Haley7d06b2e2008-06-14 17:04:49 -07002026static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08002028#ifdef CONFIG_TCP_MD5SIG
2029 /* Clean up the MD5 key list */
2030 if (tcp_sk(sk)->md5sig_info)
2031 tcp_v6_clear_md5_list(sk);
2032#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07002034 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035}
2036
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09002037#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002039static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002040 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08002043 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
2044 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045
2046 if (ttd < 0)
2047 ttd = 0;
2048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 seq_printf(seq,
2050 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
2051 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
2052 i,
2053 src->s6_addr32[0], src->s6_addr32[1],
2054 src->s6_addr32[2], src->s6_addr32[3],
KOVACS Krisztianfd507032008-10-19 23:35:58 -07002055 ntohs(inet_rsk(req)->loc_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 dest->s6_addr32[0], dest->s6_addr32[1],
2057 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07002058 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 TCP_SYN_RECV,
2060 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002061 1, /* timers active (only the expire timer) */
2062 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 req->retrans,
2064 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002065 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 0, /* open_requests have no inode */
2067 0, req);
2068}
2069
2070static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
2071{
2072 struct in6_addr *dest, *src;
2073 __u16 destp, srcp;
2074 int timer_active;
2075 unsigned long timer_expires;
2076 struct inet_sock *inet = inet_sk(sp);
2077 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002078 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 struct ipv6_pinfo *np = inet6_sk(sp);
2080
2081 dest = &np->daddr;
2082 src = &np->rcv_saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +00002083 destp = ntohs(inet->inet_dport);
2084 srcp = ntohs(inet->inet_sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002085
2086 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002088 timer_expires = icsk->icsk_timeout;
2089 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002091 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 } else if (timer_pending(&sp->sk_timer)) {
2093 timer_active = 2;
2094 timer_expires = sp->sk_timer.expires;
2095 } else {
2096 timer_active = 0;
2097 timer_expires = jiffies;
2098 }
2099
2100 seq_printf(seq,
2101 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Stephen Hemminger7be87352008-06-27 20:00:19 -07002102 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 i,
2104 src->s6_addr32[0], src->s6_addr32[1],
2105 src->s6_addr32[2], src->s6_addr32[3], srcp,
2106 dest->s6_addr32[0], dest->s6_addr32[1],
2107 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002108 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07002109 tp->write_seq-tp->snd_una,
2110 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 timer_active,
2112 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002113 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03002115 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 sock_i_ino(sp),
2117 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07002118 jiffies_to_clock_t(icsk->icsk_rto),
2119 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002120 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07002121 tp->snd_cwnd,
2122 tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 );
2124}
2125
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002126static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07002127 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128{
2129 struct in6_addr *dest, *src;
2130 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002131 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 int ttd = tw->tw_ttd - jiffies;
2133
2134 if (ttd < 0)
2135 ttd = 0;
2136
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002137 dest = &tw6->tw_v6_daddr;
2138 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 destp = ntohs(tw->tw_dport);
2140 srcp = ntohs(tw->tw_sport);
2141
2142 seq_printf(seq,
2143 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
2144 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
2145 i,
2146 src->s6_addr32[0], src->s6_addr32[1],
2147 src->s6_addr32[2], src->s6_addr32[3], srcp,
2148 dest->s6_addr32[0], dest->s6_addr32[1],
2149 dest->s6_addr32[2], dest->s6_addr32[3], destp,
2150 tw->tw_substate, 0, 0,
2151 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
2152 atomic_read(&tw->tw_refcnt), tw);
2153}
2154
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155static int tcp6_seq_show(struct seq_file *seq, void *v)
2156{
2157 struct tcp_iter_state *st;
2158
2159 if (v == SEQ_START_TOKEN) {
2160 seq_puts(seq,
2161 " sl "
2162 "local_address "
2163 "remote_address "
2164 "st tx_queue rx_queue tr tm->when retrnsmt"
2165 " uid timeout inode\n");
2166 goto out;
2167 }
2168 st = seq->private;
2169
2170 switch (st->state) {
2171 case TCP_SEQ_STATE_LISTENING:
2172 case TCP_SEQ_STATE_ESTABLISHED:
2173 get_tcp6_sock(seq, v, st->num);
2174 break;
2175 case TCP_SEQ_STATE_OPENREQ:
2176 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
2177 break;
2178 case TCP_SEQ_STATE_TIME_WAIT:
2179 get_timewait6_sock(seq, v, st->num);
2180 break;
2181 }
2182out:
2183 return 0;
2184}
2185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 .name = "tcp6",
2188 .family = AF_INET6,
Denis V. Lunev5f4472c2008-04-13 22:13:53 -07002189 .seq_fops = {
2190 .owner = THIS_MODULE,
2191 },
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07002192 .seq_ops = {
2193 .show = tcp6_seq_show,
2194 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195};
2196
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002197int __net_init tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002199 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200}
2201
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002202void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002204 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205}
2206#endif
2207
2208struct proto tcpv6_prot = {
2209 .name = "TCPv6",
2210 .owner = THIS_MODULE,
2211 .close = tcp_close,
2212 .connect = tcp_v6_connect,
2213 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002214 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 .ioctl = tcp_ioctl,
2216 .init = tcp_v6_init_sock,
2217 .destroy = tcp_v6_destroy_sock,
2218 .shutdown = tcp_shutdown,
2219 .setsockopt = tcp_setsockopt,
2220 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 .recvmsg = tcp_recvmsg,
Changli Gao7ba42912010-07-10 20:41:55 +00002222 .sendmsg = tcp_sendmsg,
2223 .sendpage = tcp_sendpage,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 .backlog_rcv = tcp_v6_do_rcv,
2225 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08002226 .unhash = inet_unhash,
2227 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 .enter_memory_pressure = tcp_enter_memory_pressure,
2229 .sockets_allocated = &tcp_sockets_allocated,
2230 .memory_allocated = &tcp_memory_allocated,
2231 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002232 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 .sysctl_mem = sysctl_tcp_mem,
2234 .sysctl_wmem = sysctl_tcp_wmem,
2235 .sysctl_rmem = sysctl_tcp_rmem,
2236 .max_header = MAX_TCP_HEADER,
2237 .obj_size = sizeof(struct tcp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08002238 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002239 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002240 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002241 .h.hashinfo = &tcp_hashinfo,
Changli Gao7ba42912010-07-10 20:41:55 +00002242 .no_autobind = true,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002243#ifdef CONFIG_COMPAT
2244 .compat_setsockopt = compat_tcp_setsockopt,
2245 .compat_getsockopt = compat_tcp_getsockopt,
2246#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247};
2248
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00002249static const struct inet6_protocol tcpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 .handler = tcp_v6_rcv,
2251 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002252 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002253 .gso_segment = tcp_tso_segment,
Herbert Xu684f2172009-01-08 10:41:23 -08002254 .gro_receive = tcp6_gro_receive,
2255 .gro_complete = tcp6_gro_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2257};
2258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259static struct inet_protosw tcpv6_protosw = {
2260 .type = SOCK_STREAM,
2261 .protocol = IPPROTO_TCP,
2262 .prot = &tcpv6_prot,
2263 .ops = &inet6_stream_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002265 .flags = INET_PROTOSW_PERMANENT |
2266 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267};
2268
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002269static int __net_init tcpv6_net_init(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002270{
Denis V. Lunev56772422008-04-03 14:28:30 -07002271 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2272 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002273}
2274
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002275static void __net_exit tcpv6_net_exit(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002276{
Denis V. Lunev56772422008-04-03 14:28:30 -07002277 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002278}
2279
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002280static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002281{
2282 inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002283}
2284
2285static struct pernet_operations tcpv6_net_ops = {
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002286 .init = tcpv6_net_init,
2287 .exit = tcpv6_net_exit,
2288 .exit_batch = tcpv6_net_exit_batch,
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002289};
2290
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002291int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002293 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002294
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002295 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2296 if (ret)
2297 goto out;
2298
2299 /* register inet6 protocol */
2300 ret = inet6_register_protosw(&tcpv6_protosw);
2301 if (ret)
2302 goto out_tcpv6_protocol;
2303
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002304 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002305 if (ret)
2306 goto out_tcpv6_protosw;
2307out:
2308 return ret;
2309
2310out_tcpv6_protocol:
2311 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2312out_tcpv6_protosw:
2313 inet6_unregister_protosw(&tcpv6_protosw);
2314 goto out;
2315}
2316
Daniel Lezcano09f77092007-12-13 05:34:58 -08002317void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002318{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002319 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002320 inet6_unregister_protosw(&tcpv6_protosw);
2321 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322}