blob: f37769ea63755c8c00eac9496c085c33abad9225 [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>
David S. Miller6e5714e2011-08-03 20:50:44 -070064#include <net/secure_seq.h>
Glauber Costad1a4c0b2011-12-11 21:47:04 +000065#include <net/tcp_memcontrol.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include <asm/uaccess.h>
68
69#include <linux/proc_fs.h>
70#include <linux/seq_file.h>
71
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080072#include <linux/crypto.h>
73#include <linux/scatterlist.h>
74
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080075static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
Gui Jianfeng6edafaa2008-08-06 23:50:04 -070076static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
77 struct request_sock *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Herbert Xu8ad50d92010-04-11 02:15:54 +000080static void __tcp_v6_send_check(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000081 const struct in6_addr *saddr,
82 const struct in6_addr *daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Stephen Hemminger3b401a82009-09-01 19:25:04 +000084static const struct inet_connection_sock_af_ops ipv6_mapped;
85static const struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080086#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +000087static const struct tcp_sock_af_ops tcp_sock_ipv6_specific;
88static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090089#else
90static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
Eric Dumazetb71d1d42011-04-22 04:53:02 +000091 const struct in6_addr *addr)
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090092{
93 return NULL;
94}
David S. Millera9286302006-11-14 19:53:22 -080095#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Linus Torvalds1da177e2005-04-16 15:20:36 -070097static void tcp_v6_hash(struct sock *sk)
98{
99 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800100 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 tcp_prot.hash(sk);
102 return;
103 }
104 local_bh_disable();
Eric Dumazet9327f702009-12-04 03:46:54 +0000105 __inet6_hash(sk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 local_bh_enable();
107 }
108}
109
Herbert Xu684f2172009-01-08 10:41:23 -0800110static __inline__ __sum16 tcp_v6_check(int len,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000111 const struct in6_addr *saddr,
112 const struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800113 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
115 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
116}
117
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400118static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700120 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
121 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700122 tcp_hdr(skb)->dest,
123 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124}
125
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900126static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 int addr_len)
128{
129 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900130 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800131 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 struct ipv6_pinfo *np = inet6_sk(sk);
133 struct tcp_sock *tp = tcp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000134 struct in6_addr *saddr = NULL, *final_p, final;
David S. Miller493f3772010-12-02 12:14:29 -0800135 struct rt6_info *rt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500136 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct dst_entry *dst;
138 int addr_type;
139 int err;
140
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900141 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 return -EINVAL;
143
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900144 if (usin->sin6_family != AF_INET6)
Eric Dumazeta02cec22010-09-22 20:43:57 +0000145 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
David S. Miller4c9483b2011-03-12 16:22:43 -0500147 memset(&fl6, 0, sizeof(fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 if (np->sndflow) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500150 fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
151 IP6_ECN_flow_init(fl6.flowlabel);
152 if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 struct ip6_flowlabel *flowlabel;
David S. Miller4c9483b2011-03-12 16:22:43 -0500154 flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 if (flowlabel == NULL)
156 return -EINVAL;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000157 usin->sin6_addr = flowlabel->dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 fl6_sock_release(flowlabel);
159 }
160 }
161
162 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900163 * connect() to INADDR_ANY means loopback (BSD'ism).
164 */
165
166 if(ipv6_addr_any(&usin->sin6_addr))
167 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169 addr_type = ipv6_addr_type(&usin->sin6_addr);
170
171 if(addr_type & IPV6_ADDR_MULTICAST)
172 return -ENETUNREACH;
173
174 if (addr_type&IPV6_ADDR_LINKLOCAL) {
175 if (addr_len >= sizeof(struct sockaddr_in6) &&
176 usin->sin6_scope_id) {
177 /* If interface is set while binding, indices
178 * must coincide.
179 */
180 if (sk->sk_bound_dev_if &&
181 sk->sk_bound_dev_if != usin->sin6_scope_id)
182 return -EINVAL;
183
184 sk->sk_bound_dev_if = usin->sin6_scope_id;
185 }
186
187 /* Connect to link-local address requires an interface */
188 if (!sk->sk_bound_dev_if)
189 return -EINVAL;
190 }
191
192 if (tp->rx_opt.ts_recent_stamp &&
193 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
194 tp->rx_opt.ts_recent = 0;
195 tp->rx_opt.ts_recent_stamp = 0;
196 tp->write_seq = 0;
197 }
198
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000199 np->daddr = usin->sin6_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500200 np->flow_label = fl6.flowlabel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 /*
203 * TCP over IPv4
204 */
205
206 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800207 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 struct sockaddr_in sin;
209
210 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
211
212 if (__ipv6_only_sock(sk))
213 return -ENETUNREACH;
214
215 sin.sin_family = AF_INET;
216 sin.sin_port = usin->sin6_port;
217 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
218
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800219 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800221#ifdef CONFIG_TCP_MD5SIG
222 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
223#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
226
227 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800228 icsk->icsk_ext_hdr_len = exthdrlen;
229 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800231#ifdef CONFIG_TCP_MD5SIG
232 tp->af_specific = &tcp_sock_ipv6_specific;
233#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 goto failure;
235 } else {
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000236 ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
237 ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
238 &np->rcv_saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 }
240
241 return err;
242 }
243
244 if (!ipv6_addr_any(&np->rcv_saddr))
245 saddr = &np->rcv_saddr;
246
David S. Miller4c9483b2011-03-12 16:22:43 -0500247 fl6.flowi6_proto = IPPROTO_TCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000248 fl6.daddr = np->daddr;
249 fl6.saddr = saddr ? *saddr : np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500250 fl6.flowi6_oif = sk->sk_bound_dev_if;
251 fl6.flowi6_mark = sk->sk_mark;
David S. Miller1958b852011-03-12 16:36:19 -0500252 fl6.fl6_dport = usin->sin6_port;
253 fl6.fl6_sport = inet->inet_sport;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
David S. Miller4c9483b2011-03-12 16:22:43 -0500255 final_p = fl6_update_dst(&fl6, np->opt, &final);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
David S. Miller4c9483b2011-03-12 16:22:43 -0500257 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700258
David S. Miller4c9483b2011-03-12 16:22:43 -0500259 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800260 if (IS_ERR(dst)) {
261 err = PTR_ERR(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 goto failure;
David S. Miller14e50e52007-05-24 18:17:54 -0700263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 if (saddr == NULL) {
David S. Miller4c9483b2011-03-12 16:22:43 -0500266 saddr = &fl6.saddr;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000267 np->rcv_saddr = *saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 }
269
270 /* set the source address */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000271 np->saddr = *saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000272 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700274 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700275 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
David S. Miller493f3772010-12-02 12:14:29 -0800277 rt = (struct rt6_info *) dst;
278 if (tcp_death_row.sysctl_tw_recycle &&
279 !tp->rx_opt.ts_recent_stamp &&
280 ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) {
281 struct inet_peer *peer = rt6_get_peer(rt);
282 /*
283 * VJ's idea. We save last timestamp seen from
284 * the destination in peer table, when entering state
285 * TIME-WAIT * and initialize rx_opt.ts_recent from it,
286 * when trying new connection.
287 */
288 if (peer) {
289 inet_peer_refcheck(peer);
290 if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
291 tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
292 tp->rx_opt.ts_recent = peer->tcp_ts;
293 }
294 }
295 }
296
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800297 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800299 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
300 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
303
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000304 inet->inet_dport = usin->sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800307 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (err)
309 goto late_failure;
310
311 if (!tp->write_seq)
312 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
313 np->daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000314 inet->inet_sport,
315 inet->inet_dport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 err = tcp_connect(sk);
318 if (err)
319 goto late_failure;
320
321 return 0;
322
323late_failure:
324 tcp_set_state(sk, TCP_CLOSE);
325 __sk_dst_reset(sk);
326failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000327 inet->inet_dport = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 sk->sk_route_caps = 0;
329 return err;
330}
331
332static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700333 u8 type, u8 code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000335 const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300336 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 struct ipv6_pinfo *np;
338 struct sock *sk;
339 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900340 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 __u32 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700342 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700344 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800345 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700348 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
349 ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return;
351 }
352
353 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700354 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return;
356 }
357
358 bh_lock_sock(sk);
359 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700360 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 if (sk->sk_state == TCP_CLOSE)
363 goto out;
364
Stephen Hemmingere802af92010-04-22 15:24:53 -0700365 if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
366 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
367 goto out;
368 }
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900371 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 if (sk->sk_state != TCP_LISTEN &&
373 !between(seq, tp->snd_una, tp->snd_nxt)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700374 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 goto out;
376 }
377
378 np = inet6_sk(sk);
379
380 if (type == ICMPV6_PKT_TOOBIG) {
David S. Miller68d0c6d2011-03-01 13:19:07 -0800381 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 if (sock_owned_by_user(sk))
384 goto out;
385 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
386 goto out;
387
388 /* icmp should have updated the destination cache entry */
389 dst = __sk_dst_check(sk, np->dst_cookie);
390
391 if (dst == NULL) {
392 struct inet_sock *inet = inet_sk(sk);
David S. Miller4c9483b2011-03-12 16:22:43 -0500393 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
395 /* BUGGG_FUTURE: Again, it is not clear how
396 to handle rthdr case. Ignore this complexity
397 for now.
398 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500399 memset(&fl6, 0, sizeof(fl6));
400 fl6.flowi6_proto = IPPROTO_TCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000401 fl6.daddr = np->daddr;
402 fl6.saddr = np->saddr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500403 fl6.flowi6_oif = sk->sk_bound_dev_if;
404 fl6.flowi6_mark = sk->sk_mark;
David S. Miller1958b852011-03-12 16:36:19 -0500405 fl6.fl6_dport = inet->inet_dport;
406 fl6.fl6_sport = inet->inet_sport;
David S. Miller4c9483b2011-03-12 16:22:43 -0500407 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
David S. Miller4c9483b2011-03-12 16:22:43 -0500409 dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800410 if (IS_ERR(dst)) {
411 sk->sk_err_soft = -PTR_ERR(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 goto out;
413 }
414
415 } else
416 dst_hold(dst);
417
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800418 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 tcp_sync_mss(sk, dst_mtu(dst));
420 tcp_simple_retransmit(sk);
421 } /* else let the usual retransmit timer handle it */
422 dst_release(dst);
423 goto out;
424 }
425
426 icmpv6_err_convert(type, code, &err);
427
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700428 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700430 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 case TCP_LISTEN:
432 if (sock_owned_by_user(sk))
433 goto out;
434
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800435 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
436 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if (!req)
438 goto out;
439
440 /* ICMPs are not backlogged, hence we cannot get
441 * an established socket here.
442 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700443 WARN_ON(req->sk != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700445 if (seq != tcp_rsk(req)->snt_isn) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700446 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 goto out;
448 }
449
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700450 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 goto out;
452
453 case TCP_SYN_SENT:
454 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900455 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 sk->sk_err = err;
458 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
459
460 tcp_done(sk);
461 } else
462 sk->sk_err_soft = err;
463 goto out;
464 }
465
466 if (!sock_owned_by_user(sk) && np->recverr) {
467 sk->sk_err = err;
468 sk->sk_error_report(sk);
469 } else
470 sk->sk_err_soft = err;
471
472out:
473 bh_unlock_sock(sk);
474 sock_put(sk);
475}
476
477
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000478static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
479 struct request_values *rvp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800481 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 struct ipv6_pinfo *np = inet6_sk(sk);
483 struct sk_buff * skb;
484 struct ipv6_txoptions *opt = NULL;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000485 struct in6_addr * final_p, final;
David S. Miller4c9483b2011-03-12 16:22:43 -0500486 struct flowi6 fl6;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800487 struct dst_entry *dst;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800488 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
David S. Miller4c9483b2011-03-12 16:22:43 -0500490 memset(&fl6, 0, sizeof(fl6));
491 fl6.flowi6_proto = IPPROTO_TCP;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000492 fl6.daddr = treq->rmt_addr;
493 fl6.saddr = treq->loc_addr;
David S. Miller4c9483b2011-03-12 16:22:43 -0500494 fl6.flowlabel = 0;
495 fl6.flowi6_oif = treq->iif;
496 fl6.flowi6_mark = sk->sk_mark;
David S. Miller1958b852011-03-12 16:36:19 -0500497 fl6.fl6_dport = inet_rsk(req)->rmt_port;
498 fl6.fl6_sport = inet_rsk(req)->loc_port;
David S. Miller4c9483b2011-03-12 16:22:43 -0500499 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800501 opt = np->opt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500502 final_p = fl6_update_dst(&fl6, opt, &final);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
David S. Miller4c9483b2011-03-12 16:22:43 -0500504 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800505 if (IS_ERR(dst)) {
506 err = PTR_ERR(dst);
Boris Ostrovsky738faca2011-04-04 13:07:26 -0700507 dst = NULL;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800508 goto done;
David S. Miller68d0c6d2011-03-01 13:19:07 -0800509 }
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000510 skb = tcp_make_synack(sk, dst, req, rvp);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800511 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (skb) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000513 __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000515 fl6.daddr = treq->rmt_addr;
Eric Dumazetb903d322011-10-27 00:44:35 -0400516 err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200517 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 }
519
520done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900521 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800523 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return err;
525}
526
Octavian Purdila72659ec2010-01-17 19:09:39 -0800527static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
528 struct request_values *rvp)
529{
530 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
531 return tcp_v6_send_synack(sk, req, rvp);
532}
533
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700534static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
Wei Yongjun800d55f2009-02-23 21:45:33 +0000536 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800539#ifdef CONFIG_TCP_MD5SIG
540static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000541 const struct in6_addr *addr)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800542{
543 struct tcp_sock *tp = tcp_sk(sk);
544 int i;
545
546 BUG_ON(tp == NULL);
547
548 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
549 return NULL;
550
551 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900552 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
David S. Millerf8ab18d2007-09-28 15:18:35 -0700553 return &tp->md5sig_info->keys6[i].base;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800554 }
555 return NULL;
556}
557
558static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
559 struct sock *addr_sk)
560{
561 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
562}
563
564static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
565 struct request_sock *req)
566{
567 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
568}
569
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000570static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800571 char *newkey, u8 newkeylen)
572{
573 /* Add key to the list */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700574 struct tcp_md5sig_key *key;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800575 struct tcp_sock *tp = tcp_sk(sk);
576 struct tcp6_md5sig_key *keys;
577
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700578 key = tcp_v6_md5_do_lookup(sk, peer);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800579 if (key) {
580 /* modify existing entry - just update that one */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700581 kfree(key->key);
582 key->key = newkey;
583 key->keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800584 } else {
585 /* reallocate new list if current one is full. */
586 if (!tp->md5sig_info) {
587 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
588 if (!tp->md5sig_info) {
589 kfree(newkey);
590 return -ENOMEM;
591 }
Eric Dumazeta4654192010-05-16 00:36:33 -0700592 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800593 }
Yan, Zheng260fcbe2011-09-29 17:10:10 +0000594 if (tp->md5sig_info->entries6 == 0 &&
595 tcp_alloc_md5sig_pool(sk) == NULL) {
YOSHIFUJI Hideakiaacbe8c2007-11-20 17:30:56 -0800596 kfree(newkey);
597 return -ENOMEM;
598 }
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800599 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
600 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
601 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
602
603 if (!keys) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800604 kfree(newkey);
Yan, Zheng260fcbe2011-09-29 17:10:10 +0000605 if (tp->md5sig_info->entries6 == 0)
606 tcp_free_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800607 return -ENOMEM;
608 }
609
610 if (tp->md5sig_info->entries6)
611 memmove(keys, tp->md5sig_info->keys6,
612 (sizeof (tp->md5sig_info->keys6[0]) *
613 tp->md5sig_info->entries6));
614
615 kfree(tp->md5sig_info->keys6);
616 tp->md5sig_info->keys6 = keys;
617 tp->md5sig_info->alloced6++;
618 }
619
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000620 tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr = *peer;
David S. Millerf8ab18d2007-09-28 15:18:35 -0700621 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
622 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800623
624 tp->md5sig_info->entries6++;
625 }
626 return 0;
627}
628
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000629static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800630{
631 struct tcp_sock *tp = tcp_sk(sk);
632 int i;
633
634 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900635 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800636 /* Free the key */
David S. Millerf8ab18d2007-09-28 15:18:35 -0700637 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800638 tp->md5sig_info->entries6--;
639
640 if (tp->md5sig_info->entries6 == 0) {
641 kfree(tp->md5sig_info->keys6);
642 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700643 tp->md5sig_info->alloced6 = 0;
Yan, Zheng260fcbe2011-09-29 17:10:10 +0000644 tcp_free_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800645 } else {
646 /* shrink the database */
647 if (tp->md5sig_info->entries6 != i)
648 memmove(&tp->md5sig_info->keys6[i],
649 &tp->md5sig_info->keys6[i+1],
650 (tp->md5sig_info->entries6 - i)
651 * sizeof (tp->md5sig_info->keys6[0]));
652 }
YOSHIFUJI Hideaki77adefd2007-11-20 17:31:23 -0800653 return 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800654 }
655 }
656 return -ENOENT;
657}
658
659static void tcp_v6_clear_md5_list (struct sock *sk)
660{
661 struct tcp_sock *tp = tcp_sk(sk);
662 int i;
663
664 if (tp->md5sig_info->entries6) {
665 for (i = 0; i < tp->md5sig_info->entries6; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700666 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800667 tp->md5sig_info->entries6 = 0;
668 tcp_free_md5sig_pool();
669 }
670
671 kfree(tp->md5sig_info->keys6);
672 tp->md5sig_info->keys6 = NULL;
673 tp->md5sig_info->alloced6 = 0;
674
675 if (tp->md5sig_info->entries4) {
676 for (i = 0; i < tp->md5sig_info->entries4; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700677 kfree(tp->md5sig_info->keys4[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800678 tp->md5sig_info->entries4 = 0;
679 tcp_free_md5sig_pool();
680 }
681
682 kfree(tp->md5sig_info->keys4);
683 tp->md5sig_info->keys4 = NULL;
684 tp->md5sig_info->alloced4 = 0;
685}
686
687static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
688 int optlen)
689{
690 struct tcp_md5sig cmd;
691 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
692 u8 *newkey;
693
694 if (optlen < sizeof(cmd))
695 return -EINVAL;
696
697 if (copy_from_user(&cmd, optval, sizeof(cmd)))
698 return -EFAULT;
699
700 if (sin6->sin6_family != AF_INET6)
701 return -EINVAL;
702
703 if (!cmd.tcpm_keylen) {
704 if (!tcp_sk(sk)->md5sig_info)
705 return -ENOENT;
Brian Haleye773e4f2007-08-24 23:16:08 -0700706 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800707 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
708 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
709 }
710
711 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
712 return -EINVAL;
713
714 if (!tcp_sk(sk)->md5sig_info) {
715 struct tcp_sock *tp = tcp_sk(sk);
716 struct tcp_md5sig_info *p;
717
718 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
719 if (!p)
720 return -ENOMEM;
721
722 tp->md5sig_info = p;
Eric Dumazeta4654192010-05-16 00:36:33 -0700723 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800724 }
725
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200726 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800727 if (!newkey)
728 return -ENOMEM;
Brian Haleye773e4f2007-08-24 23:16:08 -0700729 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800730 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
731 newkey, cmd.tcpm_keylen);
732 }
733 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
734}
735
Adam Langley49a72df2008-07-19 00:01:42 -0700736static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000737 const struct in6_addr *daddr,
738 const struct in6_addr *saddr, int nbytes)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800739{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800740 struct tcp6_pseudohdr *bp;
Adam Langley49a72df2008-07-19 00:01:42 -0700741 struct scatterlist sg;
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900742
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800743 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800744 /* 1. TCP pseudo-header (RFC2460) */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000745 bp->saddr = *saddr;
746 bp->daddr = *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700747 bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley00b13042008-07-31 21:36:07 -0700748 bp->len = cpu_to_be32(nbytes);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800749
Adam Langley49a72df2008-07-19 00:01:42 -0700750 sg_init_one(&sg, bp, sizeof(*bp));
751 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
752}
David S. Millerc7da57a2007-10-26 00:41:21 -0700753
Adam Langley49a72df2008-07-19 00:01:42 -0700754static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000755 const struct in6_addr *daddr, struct in6_addr *saddr,
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400756 const struct tcphdr *th)
Adam Langley49a72df2008-07-19 00:01:42 -0700757{
758 struct tcp_md5sig_pool *hp;
759 struct hash_desc *desc;
760
761 hp = tcp_get_md5sig_pool();
762 if (!hp)
763 goto clear_hash_noput;
764 desc = &hp->md5_desc;
765
766 if (crypto_hash_init(desc))
767 goto clear_hash;
768 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
769 goto clear_hash;
770 if (tcp_md5_hash_header(hp, th))
771 goto clear_hash;
772 if (tcp_md5_hash_key(hp, key))
773 goto clear_hash;
774 if (crypto_hash_final(desc, md5_hash))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800775 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800776
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800777 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800778 return 0;
Adam Langley49a72df2008-07-19 00:01:42 -0700779
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800780clear_hash:
781 tcp_put_md5sig_pool();
782clear_hash_noput:
783 memset(md5_hash, 0, 16);
Adam Langley49a72df2008-07-19 00:01:42 -0700784 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800785}
786
Adam Langley49a72df2008-07-19 00:01:42 -0700787static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400788 const struct sock *sk,
789 const struct request_sock *req,
790 const struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800791{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000792 const struct in6_addr *saddr, *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700793 struct tcp_md5sig_pool *hp;
794 struct hash_desc *desc;
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400795 const struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800796
797 if (sk) {
798 saddr = &inet6_sk(sk)->saddr;
799 daddr = &inet6_sk(sk)->daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700800 } else if (req) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800801 saddr = &inet6_rsk(req)->loc_addr;
802 daddr = &inet6_rsk(req)->rmt_addr;
Adam Langley49a72df2008-07-19 00:01:42 -0700803 } else {
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000804 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
Adam Langley49a72df2008-07-19 00:01:42 -0700805 saddr = &ip6h->saddr;
806 daddr = &ip6h->daddr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800807 }
Adam Langley49a72df2008-07-19 00:01:42 -0700808
809 hp = tcp_get_md5sig_pool();
810 if (!hp)
811 goto clear_hash_noput;
812 desc = &hp->md5_desc;
813
814 if (crypto_hash_init(desc))
815 goto clear_hash;
816
817 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
818 goto clear_hash;
819 if (tcp_md5_hash_header(hp, th))
820 goto clear_hash;
821 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
822 goto clear_hash;
823 if (tcp_md5_hash_key(hp, key))
824 goto clear_hash;
825 if (crypto_hash_final(desc, md5_hash))
826 goto clear_hash;
827
828 tcp_put_md5sig_pool();
829 return 0;
830
831clear_hash:
832 tcp_put_md5sig_pool();
833clear_hash_noput:
834 memset(md5_hash, 0, 16);
835 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800836}
837
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400838static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800839{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400840 const __u8 *hash_location = NULL;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800841 struct tcp_md5sig_key *hash_expected;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000842 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400843 const struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800844 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800845 u8 newhash[16];
846
847 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900848 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800849
David S. Miller785957d2008-07-30 03:03:15 -0700850 /* We've parsed the options - do we have a hash? */
851 if (!hash_expected && !hash_location)
852 return 0;
853
854 if (hash_expected && !hash_location) {
855 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800856 return 1;
857 }
858
David S. Miller785957d2008-07-30 03:03:15 -0700859 if (!hash_expected && hash_location) {
860 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800861 return 1;
862 }
863
864 /* check the signature */
Adam Langley49a72df2008-07-19 00:01:42 -0700865 genhash = tcp_v6_md5_hash_skb(newhash,
866 hash_expected,
867 NULL, NULL, skb);
868
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800869 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
870 if (net_ratelimit()) {
Joe Perches5856b602010-01-08 00:59:52 -0800871 printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800872 genhash ? "failed" : "mismatch",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700873 &ip6h->saddr, ntohs(th->source),
874 &ip6h->daddr, ntohs(th->dest));
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800875 }
876 return 1;
877 }
878 return 0;
879}
880#endif
881
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800882struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700884 .obj_size = sizeof(struct tcp6_request_sock),
Octavian Purdila72659ec2010-01-17 19:09:39 -0800885 .rtx_syn_ack = tcp_v6_rtx_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700886 .send_ack = tcp_v6_reqsk_send_ack,
887 .destructor = tcp_v6_reqsk_destructor,
Octavian Purdila72659ec2010-01-17 19:09:39 -0800888 .send_reset = tcp_v6_send_reset,
889 .syn_ack_timeout = tcp_syn_ack_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890};
891
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800892#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +0000893static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800894 .md5_lookup = tcp_v6_reqsk_md5_lookup,
John Dykstrae3afe7b2009-07-16 05:04:51 +0000895 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800896};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800897#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800898
Herbert Xu8ad50d92010-04-11 02:15:54 +0000899static void __tcp_v6_send_check(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000900 const struct in6_addr *saddr, const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700902 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
Patrick McHardy84fa7932006-08-29 16:44:56 -0700904 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000905 th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700906 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800907 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 } else {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000909 th->check = tcp_v6_check(skb->len, saddr, daddr,
910 csum_partial(th, th->doff << 2,
911 skb->csum));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 }
913}
914
Herbert Xubb296242010-04-11 02:15:55 +0000915static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Herbert Xu8ad50d92010-04-11 02:15:54 +0000916{
917 struct ipv6_pinfo *np = inet6_sk(sk);
918
919 __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
920}
921
Herbert Xua430a432006-07-08 13:34:56 -0700922static int tcp_v6_gso_send_check(struct sk_buff *skb)
923{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000924 const struct ipv6hdr *ipv6h;
Herbert Xua430a432006-07-08 13:34:56 -0700925 struct tcphdr *th;
926
927 if (!pskb_may_pull(skb, sizeof(*th)))
928 return -EINVAL;
929
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700930 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700931 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700932
933 th->check = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -0700934 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xu8ad50d92010-04-11 02:15:54 +0000935 __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
Herbert Xua430a432006-07-08 13:34:56 -0700936 return 0;
937}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Herbert Xu36990672009-05-22 00:45:28 -0700939static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
940 struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800941{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000942 const struct ipv6hdr *iph = skb_gro_network_header(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800943
944 switch (skb->ip_summed) {
945 case CHECKSUM_COMPLETE:
Herbert Xu86911732009-01-29 14:19:50 +0000946 if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
Herbert Xu684f2172009-01-08 10:41:23 -0800947 skb->csum)) {
948 skb->ip_summed = CHECKSUM_UNNECESSARY;
949 break;
950 }
951
952 /* fall through */
953 case CHECKSUM_NONE:
954 NAPI_GRO_CB(skb)->flush = 1;
955 return NULL;
956 }
957
958 return tcp_gro_receive(head, skb);
959}
Herbert Xu684f2172009-01-08 10:41:23 -0800960
Herbert Xu36990672009-05-22 00:45:28 -0700961static int tcp6_gro_complete(struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800962{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000963 const struct ipv6hdr *iph = ipv6_hdr(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800964 struct tcphdr *th = tcp_hdr(skb);
965
966 th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
967 &iph->saddr, &iph->daddr, 0);
968 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
969
970 return tcp_gro_complete(skb);
971}
Herbert Xu684f2172009-01-08 10:41:23 -0800972
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700973static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
Eric Dumazetb903d322011-10-27 00:44:35 -0400974 u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400976 const struct tcphdr *th = tcp_hdr(skb);
977 struct tcphdr *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 struct sk_buff *buff;
David S. Miller4c9483b2011-03-12 16:22:43 -0500979 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000980 struct net *net = dev_net(skb_dst(skb)->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -0800981 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -0800982 unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazetadf30902009-06-02 05:19:30 +0000983 struct dst_entry *dst;
Al Viroe69a4ad2006-11-14 20:56:00 -0800984 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -0700987 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800988#ifdef CONFIG_TCP_MD5SIG
989 if (key)
990 tot_len += TCPOLEN_MD5SIG_ALIGNED;
991#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
994 GFP_ATOMIC);
995 if (buff == NULL)
996 return;
997
998 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
999
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001000 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Herbert Xu6651ffc2010-04-21 00:47:15 -07001001 skb_reset_transport_header(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 /* Swap the send and the receive. */
1004 memset(t1, 0, sizeof(*t1));
1005 t1->dest = th->source;
1006 t1->source = th->dest;
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001007 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 t1->seq = htonl(seq);
1009 t1->ack_seq = htonl(ack);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001010 t1->ack = !rst || !th->ack;
1011 t1->rst = rst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001013
Al Viroe69a4ad2006-11-14 20:56:00 -08001014 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001017 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1018 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
1019 *topt++ = htonl(tcp_time_stamp);
Ilpo Järvinen53b12572008-10-08 14:36:33 -07001020 *topt++ = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 }
1022
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001023#ifdef CONFIG_TCP_MD5SIG
1024 if (key) {
1025 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1026 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Adam Langley49a72df2008-07-19 00:01:42 -07001027 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
Adam Langley90b7e112008-07-31 20:49:48 -07001028 &ipv6_hdr(skb)->saddr,
1029 &ipv6_hdr(skb)->daddr, t1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001030 }
1031#endif
1032
David S. Miller4c9483b2011-03-12 16:22:43 -05001033 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001034 fl6.daddr = ipv6_hdr(skb)->saddr;
1035 fl6.saddr = ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
David S. Millere5700af2010-04-21 14:59:20 -07001037 buff->ip_summed = CHECKSUM_PARTIAL;
1038 buff->csum = 0;
1039
David S. Miller4c9483b2011-03-12 16:22:43 -05001040 __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
David S. Miller4c9483b2011-03-12 16:22:43 -05001042 fl6.flowi6_proto = IPPROTO_TCP;
1043 fl6.flowi6_oif = inet6_iif(skb);
David S. Miller1958b852011-03-12 16:36:19 -05001044 fl6.fl6_dport = t1->dest;
1045 fl6.fl6_sport = t1->source;
David S. Miller4c9483b2011-03-12 16:22:43 -05001046 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001048 /* Pass a socket to ip6_dst_lookup either it is for RST
1049 * Underlying function will use this to retrieve the network
1050 * namespace
1051 */
David S. Miller4c9483b2011-03-12 16:22:43 -05001052 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -08001053 if (!IS_ERR(dst)) {
1054 skb_dst_set(buff, dst);
Eric Dumazetb903d322011-10-27 00:44:35 -04001055 ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
David S. Miller68d0c6d2011-03-01 13:19:07 -08001056 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
1057 if (rst)
1058 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
1059 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
1061
1062 kfree_skb(buff);
1063}
1064
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001065static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
1066{
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001067 const struct tcphdr *th = tcp_hdr(skb);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001068 u32 seq = 0, ack_seq = 0;
Guo-Fu Tsengfa3e5b42008-10-09 21:11:56 -07001069 struct tcp_md5sig_key *key = NULL;
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001070
1071 if (th->rst)
1072 return;
1073
1074 if (!ipv6_unicast_destination(skb))
1075 return;
1076
1077#ifdef CONFIG_TCP_MD5SIG
1078 if (sk)
shawnlu8a622e72012-01-20 12:22:04 +00001079 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001080#endif
1081
1082 if (th->ack)
1083 seq = ntohl(th->ack_seq);
1084 else
1085 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
1086 (th->doff << 2);
1087
Eric Dumazetb903d322011-10-27 00:44:35 -04001088 tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001089}
1090
1091static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
Eric Dumazetb903d322011-10-27 00:44:35 -04001092 struct tcp_md5sig_key *key, u8 tclass)
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001093{
Eric Dumazetb903d322011-10-27 00:44:35 -04001094 tcp_v6_send_response(skb, seq, ack, win, ts, key, 0, tclass);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001095}
1096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1098{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001099 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001100 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001102 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001103 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
Eric Dumazetb903d322011-10-27 00:44:35 -04001104 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw),
1105 tw->tw_tclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001107 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
Gui Jianfeng6edafaa2008-08-06 23:50:04 -07001110static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
1111 struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001113 tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
Eric Dumazetb903d322011-10-27 00:44:35 -04001114 tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115}
1116
1117
1118static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1119{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001120 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001121 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 struct sock *nsk;
1123
1124 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001125 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001126 &ipv6_hdr(skb)->saddr,
1127 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 if (req)
1129 return tcp_check_req(sk, skb, req, prev);
1130
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001131 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001132 &ipv6_hdr(skb)->saddr, th->source,
1133 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135 if (nsk) {
1136 if (nsk->sk_state != TCP_TIME_WAIT) {
1137 bh_lock_sock(nsk);
1138 return nsk;
1139 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001140 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 return NULL;
1142 }
1143
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001144#ifdef CONFIG_SYN_COOKIES
Florian Westphalaf9b4732010-06-03 00:43:44 +00001145 if (!th->syn)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001146 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147#endif
1148 return sk;
1149}
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151/* FIXME: this is substantially similar to the ipv4 code.
1152 * Can some kind of merge be done? -- erics
1153 */
1154static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1155{
William Allen Simpson4957faa2009-12-02 18:25:27 +00001156 struct tcp_extend_values tmp_ext;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001157 struct tcp_options_received tmp_opt;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001158 const u8 *hash_location;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001159 struct request_sock *req;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001160 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 struct ipv6_pinfo *np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 struct tcp_sock *tp = tcp_sk(sk);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001163 __u32 isn = TCP_SKB_CB(skb)->when;
David S. Miller493f3772010-12-02 12:14:29 -08001164 struct dst_entry *dst = NULL;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001165 int want_cookie = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 if (skb->protocol == htons(ETH_P_IP))
1168 return tcp_v4_conn_request(sk, skb);
1169
1170 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001171 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001173 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Eric Dumazet946cedc2011-08-30 03:21:44 +00001174 want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
1175 if (!want_cookie)
1176 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
1178
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001179 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 goto drop;
1181
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001182 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if (req == NULL)
1184 goto drop;
1185
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001186#ifdef CONFIG_TCP_MD5SIG
1187 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1188#endif
1189
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 tcp_clear_options(&tmp_opt);
1191 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1192 tmp_opt.user_mss = tp->rx_opt.user_mss;
David S. Millerbb5b7c12009-12-15 20:56:42 -08001193 tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
William Allen Simpson4957faa2009-12-02 18:25:27 +00001195 if (tmp_opt.cookie_plus > 0 &&
1196 tmp_opt.saw_tstamp &&
1197 !tp->rx_opt.cookie_out_never &&
1198 (sysctl_tcp_cookie_size > 0 ||
1199 (tp->cookie_values != NULL &&
1200 tp->cookie_values->cookie_desired > 0))) {
1201 u8 *c;
1202 u32 *d;
1203 u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
1204 int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
1205
1206 if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
1207 goto drop_and_free;
1208
1209 /* Secret recipe starts with IP addresses */
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001210 d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
William Allen Simpson4957faa2009-12-02 18:25:27 +00001211 *mess++ ^= *d++;
1212 *mess++ ^= *d++;
1213 *mess++ ^= *d++;
1214 *mess++ ^= *d++;
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001215 d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
William Allen Simpson4957faa2009-12-02 18:25:27 +00001216 *mess++ ^= *d++;
1217 *mess++ ^= *d++;
1218 *mess++ ^= *d++;
1219 *mess++ ^= *d++;
1220
1221 /* plus variable length Initiator Cookie */
1222 c = (u8 *)mess;
1223 while (l-- > 0)
1224 *c++ ^= *hash_location++;
1225
William Allen Simpson4957faa2009-12-02 18:25:27 +00001226 want_cookie = 0; /* not our kind of cookie */
William Allen Simpson4957faa2009-12-02 18:25:27 +00001227 tmp_ext.cookie_out_never = 0; /* false */
1228 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1229 } else if (!tp->rx_opt.cookie_in_always) {
1230 /* redundant indications, but ensure initialization. */
1231 tmp_ext.cookie_out_never = 1; /* true */
1232 tmp_ext.cookie_plus = 0;
1233 } else {
1234 goto drop_and_free;
1235 }
1236 tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Florian Westphal4dfc2812008-04-10 03:12:40 -07001238 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001239 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1242 tcp_openreq_init(req, &tmp_opt, skb);
1243
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001244 treq = inet6_rsk(req);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001245 treq->rmt_addr = ipv6_hdr(skb)->saddr;
1246 treq->loc_addr = ipv6_hdr(skb)->daddr;
Florian Westphal172d69e2010-06-21 11:48:45 +00001247 if (!want_cookie || tmp_opt.tstamp_ok)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001248 TCP_ECN_create_request(req, tcp_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
Eric Dumazet4d0fe502011-11-23 17:29:23 -05001250 treq->iif = sk->sk_bound_dev_if;
1251
1252 /* So that link locals have meaning */
1253 if (!sk->sk_bound_dev_if &&
1254 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1255 treq->iif = inet6_iif(skb);
1256
Florian Westphal2bbdf382010-06-13 11:29:39 +00001257 if (!isn) {
David S. Miller493f3772010-12-02 12:14:29 -08001258 struct inet_peer *peer = NULL;
1259
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001260 if (ipv6_opt_accepted(sk, skb) ||
1261 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1262 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1263 atomic_inc(&skb->users);
1264 treq->pktopts = skb;
1265 }
David S. Miller493f3772010-12-02 12:14:29 -08001266
1267 if (want_cookie) {
Florian Westphal2bbdf382010-06-13 11:29:39 +00001268 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
1269 req->cookie_ts = tmp_opt.tstamp_ok;
David S. Miller493f3772010-12-02 12:14:29 -08001270 goto have_isn;
Florian Westphal2bbdf382010-06-13 11:29:39 +00001271 }
David S. Miller493f3772010-12-02 12:14:29 -08001272
1273 /* VJ's idea. We save last timestamp seen
1274 * from the destination in peer table, when entering
1275 * state TIME-WAIT, and check against it before
1276 * accepting new connection request.
1277 *
1278 * If "isn" is not zero, this request hit alive
1279 * timewait bucket, so that all the necessary checks
1280 * are made in the function processing timewait state.
1281 */
1282 if (tmp_opt.saw_tstamp &&
1283 tcp_death_row.sysctl_tw_recycle &&
1284 (dst = inet6_csk_route_req(sk, req)) != NULL &&
1285 (peer = rt6_get_peer((struct rt6_info *)dst)) != NULL &&
David S. Miller7a71ed82011-02-09 14:30:26 -08001286 ipv6_addr_equal((struct in6_addr *)peer->daddr.addr.a6,
David S. Miller493f3772010-12-02 12:14:29 -08001287 &treq->rmt_addr)) {
1288 inet_peer_refcheck(peer);
1289 if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
1290 (s32)(peer->tcp_ts - req->ts_recent) >
1291 TCP_PAWS_WINDOW) {
1292 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
1293 goto drop_and_release;
1294 }
1295 }
1296 /* Kill the following clause, if you dislike this way. */
1297 else if (!sysctl_tcp_syncookies &&
1298 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
1299 (sysctl_max_syn_backlog >> 2)) &&
1300 (!peer || !peer->tcp_ts_stamp) &&
1301 (!dst || !dst_metric(dst, RTAX_RTT))) {
1302 /* Without syncookies last quarter of
1303 * backlog is filled with destinations,
1304 * proven to be alive.
1305 * It means that we continue to communicate
1306 * to destinations, already remembered
1307 * to the moment of synflood.
1308 */
1309 LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n",
1310 &treq->rmt_addr, ntohs(tcp_hdr(skb)->source));
1311 goto drop_and_release;
1312 }
1313
1314 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001315 }
David S. Miller493f3772010-12-02 12:14:29 -08001316have_isn:
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001317 tcp_rsk(req)->snt_isn = isn;
Jerry Chu9ad7c042011-06-08 11:08:38 +00001318 tcp_rsk(req)->snt_synack = tcp_time_stamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001320 security_inet_conn_request(sk, skb, req);
1321
William Allen Simpson4957faa2009-12-02 18:25:27 +00001322 if (tcp_v6_send_synack(sk, req,
1323 (struct request_values *)&tmp_ext) ||
1324 want_cookie)
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001325 goto drop_and_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001327 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1328 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
David S. Miller493f3772010-12-02 12:14:29 -08001330drop_and_release:
1331 dst_release(dst);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001332drop_and_free:
1333 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334drop:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 return 0; /* don't send reset */
1336}
1337
1338static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001339 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 struct dst_entry *dst)
1341{
Vegard Nossum78d15e82008-09-12 16:17:43 -07001342 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1344 struct tcp6_sock *newtcp6sk;
1345 struct inet_sock *newinet;
1346 struct tcp_sock *newtp;
1347 struct sock *newsk;
1348 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001349#ifdef CONFIG_TCP_MD5SIG
1350 struct tcp_md5sig_key *key;
1351#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
1353 if (skb->protocol == htons(ETH_P_IP)) {
1354 /*
1355 * v6 mapped
1356 */
1357
1358 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1359
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001360 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 return NULL;
1362
1363 newtcp6sk = (struct tcp6_sock *)newsk;
1364 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1365
1366 newinet = inet_sk(newsk);
1367 newnp = inet6_sk(newsk);
1368 newtp = tcp_sk(newsk);
1369
1370 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1371
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001372 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001374 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001376 newnp->rcv_saddr = newnp->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001378 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001380#ifdef CONFIG_TCP_MD5SIG
1381 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1382#endif
1383
Yan, Zheng676a1182011-09-25 02:21:30 +00001384 newnp->ipv6_ac_list = NULL;
1385 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 newnp->pktoptions = NULL;
1387 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001388 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001389 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001391 /*
1392 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1393 * here, tcp_create_openreq_child now does this for us, see the comment in
1394 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
1397 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001398 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 Sync it now.
1400 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001401 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 return newsk;
1404 }
1405
Vegard Nossum78d15e82008-09-12 16:17:43 -07001406 treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 opt = np->opt;
1408
1409 if (sk_acceptq_is_full(sk))
1410 goto out_overflow;
1411
David S. Miller493f3772010-12-02 12:14:29 -08001412 if (!dst) {
1413 dst = inet6_csk_route_req(sk, req);
1414 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 newsk = tcp_create_openreq_child(sk, req, skb);
1419 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +02001420 goto out_nonewsk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001422 /*
1423 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1424 * count here, tcp_create_openreq_child now does this for us, see the
1425 * comment in that function for the gory details. -acme
1426 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Stephen Hemminger59eed272006-08-25 15:55:43 -07001428 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001429 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 newtcp6sk = (struct tcp6_sock *)newsk;
1432 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1433
1434 newtp = tcp_sk(newsk);
1435 newinet = inet_sk(newsk);
1436 newnp = inet6_sk(newsk);
1437
1438 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1439
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001440 newnp->daddr = treq->rmt_addr;
1441 newnp->saddr = treq->loc_addr;
1442 newnp->rcv_saddr = treq->loc_addr;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001443 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001445 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
1447 First: no IPv4 options.
1448 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +00001449 newinet->inet_opt = NULL;
Yan, Zheng676a1182011-09-25 02:21:30 +00001450 newnp->ipv6_ac_list = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001451 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
1453 /* Clone RX bits */
1454 newnp->rxopt.all = np->rxopt.all;
1455
1456 /* Clone pktoptions received with SYN */
1457 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001458 if (treq->pktopts != NULL) {
1459 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1460 kfree_skb(treq->pktopts);
1461 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 if (newnp->pktoptions)
1463 skb_set_owner_r(newnp->pktoptions, newsk);
1464 }
1465 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001466 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001467 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
1469 /* Clone native IPv6 options from listening socket (if any)
1470
1471 Yes, keeping reference count would be much more clever,
1472 but we make one more one thing there: reattach optmem
1473 to newsk.
1474 */
1475 if (opt) {
1476 newnp->opt = ipv6_dup_options(newsk, opt);
1477 if (opt != np->opt)
1478 sock_kfree_s(sk, opt, opt->tot_len);
1479 }
1480
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001481 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001483 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1484 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
John Heffner5d424d52006-03-20 17:53:41 -08001486 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 tcp_sync_mss(newsk, dst_mtu(dst));
David S. Miller0dbaee32010-12-13 12:52:14 -08001488 newtp->advmss = dst_metric_advmss(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 tcp_initialize_rcv_mss(newsk);
Jerry Chu9ad7c042011-06-08 11:08:38 +00001490 if (tcp_rsk(req)->snt_synack)
1491 tcp_valid_rtt_meas(newsk,
1492 tcp_time_stamp - tcp_rsk(req)->snt_synack);
1493 newtp->total_retrans = req->retrans;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001495 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
1496 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001498#ifdef CONFIG_TCP_MD5SIG
1499 /* Copy over the MD5 key from the original socket */
1500 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1501 /* We're using one, so create a matching key
1502 * on the newsk structure. If we fail to get
1503 * memory, then we end up not copying the key
1504 * across. Shucks.
1505 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001506 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1507 if (newkey != NULL)
John Dykstrae547bc12009-07-17 09:23:22 +00001508 tcp_v6_md5_do_add(newsk, &newnp->daddr,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001509 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001510 }
1511#endif
1512
Balazs Scheidler093d2822010-10-21 13:06:43 +02001513 if (__inet_inherit_port(sk, newsk) < 0) {
1514 sock_put(newsk);
1515 goto out;
1516 }
Eric Dumazet9327f702009-12-04 03:46:54 +00001517 __inet6_hash(newsk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
1519 return newsk;
1520
1521out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001522 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001523out_nonewsk:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (opt && opt != np->opt)
1525 sock_kfree_s(sk, opt, opt->tot_len);
1526 dst_release(dst);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001527out:
1528 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 return NULL;
1530}
1531
Al Virob51655b2006-11-14 21:40:42 -08001532static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001534 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Herbert Xu684f2172009-01-08 10:41:23 -08001535 if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001536 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001537 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001541
Herbert Xu684f2172009-01-08 10:41:23 -08001542 skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001543 &ipv6_hdr(skb)->saddr,
1544 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001547 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 }
1549 return 0;
1550}
1551
1552/* The socket must have it's spinlock held when we get
1553 * here.
1554 *
1555 * We have a potential double-lock case here, so even when
1556 * doing backlog processing we use the BH locking scheme.
1557 * This is because we cannot sleep with the original spinlock
1558 * held.
1559 */
1560static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1561{
1562 struct ipv6_pinfo *np = inet6_sk(sk);
1563 struct tcp_sock *tp;
1564 struct sk_buff *opt_skb = NULL;
1565
1566 /* Imagine: socket is IPv6. IPv4 packet arrives,
1567 goes to IPv4 receive handler and backlogged.
1568 From backlog it always goes here. Kerboom...
1569 Fortunately, tcp_rcv_established and rcv_established
1570 handle them correctly, but it is not case with
1571 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1572 */
1573
1574 if (skb->protocol == htons(ETH_P_IP))
1575 return tcp_v4_do_rcv(sk, skb);
1576
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001577#ifdef CONFIG_TCP_MD5SIG
1578 if (tcp_v6_inbound_md5_hash (sk, skb))
1579 goto discard;
1580#endif
1581
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001582 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 goto discard;
1584
1585 /*
1586 * socket locking is here for SMP purposes as backlog rcv
1587 * is currently called with bh processing disabled.
1588 */
1589
1590 /* Do Stevens' IPV6_PKTOPTIONS.
1591
1592 Yes, guys, it is the only place in our code, where we
1593 may make it not affecting IPv4.
1594 The rest of code is protocol independent,
1595 and I do not like idea to uglify IPv4.
1596
1597 Actually, all the idea behind IPV6_PKTOPTIONS
1598 looks not very well thought. For now we latch
1599 options, received in the last packet, enqueued
1600 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001601 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 */
1603 if (np->rxopt.all)
1604 opt_skb = skb_clone(skb, GFP_ATOMIC);
1605
1606 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
Tom Herbertbdeab992011-08-14 19:45:55 +00001607 sock_rps_save_rxhash(sk, skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001608 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 goto reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if (opt_skb)
1611 goto ipv6_pktoptions;
1612 return 0;
1613 }
1614
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001615 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 goto csum_err;
1617
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001618 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1620 if (!nsk)
1621 goto discard;
1622
1623 /*
1624 * Queue it on the new socket if the new socket is active,
1625 * otherwise we just shortcircuit this and continue with
1626 * the new socket..
1627 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001628 if(nsk != sk) {
Tom Herbertbdeab992011-08-14 19:45:55 +00001629 sock_rps_save_rxhash(nsk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 if (tcp_child_process(sk, nsk, skb))
1631 goto reset;
1632 if (opt_skb)
1633 __kfree_skb(opt_skb);
1634 return 0;
1635 }
Neil Horman47482f12011-04-06 13:07:09 -07001636 } else
Tom Herbertbdeab992011-08-14 19:45:55 +00001637 sock_rps_save_rxhash(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001639 if (tcp_rcv_state_process(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
1645reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001646 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647discard:
1648 if (opt_skb)
1649 __kfree_skb(opt_skb);
1650 kfree_skb(skb);
1651 return 0;
1652csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001653 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 goto discard;
1655
1656
1657ipv6_pktoptions:
1658 /* Do you ask, what is it?
1659
1660 1. skb was enqueued by tcp.
1661 2. skb is added to tail of read queue, rather than out of order.
1662 3. socket is not in passive state.
1663 4. Finally, it really contains options, which user wants to receive.
1664 */
1665 tp = tcp_sk(sk);
1666 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1667 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001668 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001669 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001670 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001671 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (ipv6_opt_accepted(sk, opt_skb)) {
1673 skb_set_owner_r(opt_skb, sk);
1674 opt_skb = xchg(&np->pktoptions, opt_skb);
1675 } else {
1676 __kfree_skb(opt_skb);
1677 opt_skb = xchg(&np->pktoptions, NULL);
1678 }
1679 }
1680
Wei Yongjun800d55f2009-02-23 21:45:33 +00001681 kfree_skb(opt_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 return 0;
1683}
1684
Herbert Xue5bbef22007-10-15 12:50:28 -07001685static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686{
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001687 const struct tcphdr *th;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001688 const struct ipv6hdr *hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 struct sock *sk;
1690 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001691 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 if (skb->pkt_type != PACKET_HOST)
1694 goto discard_it;
1695
1696 /*
1697 * Count it even if it's bad.
1698 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001699 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
1701 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1702 goto discard_it;
1703
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001704 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
1706 if (th->doff < sizeof(struct tcphdr)/4)
1707 goto bad_packet;
1708 if (!pskb_may_pull(skb, th->doff*4))
1709 goto discard_it;
1710
Herbert Xu60476372007-04-09 11:59:39 -07001711 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 goto bad_packet;
1713
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001714 th = tcp_hdr(skb);
Stephen Hemmingere802af92010-04-22 15:24:53 -07001715 hdr = ipv6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1717 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1718 skb->len - th->doff*4);
1719 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1720 TCP_SKB_CB(skb)->when = 0;
Eric Dumazetb82d1bb2011-09-27 02:20:08 -04001721 TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 TCP_SKB_CB(skb)->sacked = 0;
1723
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -07001724 sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 if (!sk)
1726 goto no_tcp_socket;
1727
1728process:
1729 if (sk->sk_state == TCP_TIME_WAIT)
1730 goto do_time_wait;
1731
Stephen Hemmingere802af92010-04-22 15:24:53 -07001732 if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) {
1733 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
1734 goto discard_and_relse;
1735 }
1736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1738 goto discard_and_relse;
1739
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001740 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 goto discard_and_relse;
1742
1743 skb->dev = NULL;
1744
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001745 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 ret = 0;
1747 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001748#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001749 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001750 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
Dan Williamsf67b4592009-01-06 11:38:15 -07001751 tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001752 if (tp->ucopy.dma_chan)
1753 ret = tcp_v6_do_rcv(sk, skb);
1754 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001755#endif
1756 {
1757 if (!tcp_prequeue(sk, skb))
1758 ret = tcp_v6_do_rcv(sk, skb);
1759 }
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001760 } else if (unlikely(sk_add_backlog(sk, skb))) {
Zhu Yi6b03a532010-03-04 18:01:41 +00001761 bh_unlock_sock(sk);
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001762 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
Zhu Yi6b03a532010-03-04 18:01:41 +00001763 goto discard_and_relse;
1764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 bh_unlock_sock(sk);
1766
1767 sock_put(sk);
1768 return ret ? -1 : 0;
1769
1770no_tcp_socket:
1771 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1772 goto discard_it;
1773
1774 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1775bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001776 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001778 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 }
1780
1781discard_it:
1782
1783 /*
1784 * Discard frame
1785 */
1786
1787 kfree_skb(skb);
1788 return 0;
1789
1790discard_and_relse:
1791 sock_put(sk);
1792 goto discard_it;
1793
1794do_time_wait:
1795 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001796 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 goto discard_it;
1798 }
1799
1800 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001801 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001802 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 goto discard_it;
1804 }
1805
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001806 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 case TCP_TW_SYN:
1808 {
1809 struct sock *sk2;
1810
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001811 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001812 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001813 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001815 struct inet_timewait_sock *tw = inet_twsk(sk);
1816 inet_twsk_deschedule(tw, &tcp_death_row);
1817 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 sk = sk2;
1819 goto process;
1820 }
1821 /* Fall through to ACK */
1822 }
1823 case TCP_TW_ACK:
1824 tcp_v6_timewait_ack(sk, skb);
1825 break;
1826 case TCP_TW_RST:
1827 goto no_tcp_socket;
1828 case TCP_TW_SUCCESS:;
1829 }
1830 goto discard_it;
1831}
1832
David S. Millerccb7c412010-12-01 18:09:13 -08001833static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834{
David S. Millerdb3949c2010-12-02 11:52:07 -08001835 struct rt6_info *rt = (struct rt6_info *) __sk_dst_get(sk);
1836 struct ipv6_pinfo *np = inet6_sk(sk);
1837 struct inet_peer *peer;
1838
1839 if (!rt ||
1840 !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr)) {
1841 peer = inet_getpeer_v6(&np->daddr, 1);
1842 *release_it = true;
1843 } else {
1844 if (!rt->rt6i_peer)
1845 rt6_bind_peer(rt, 1);
1846 peer = rt->rt6i_peer;
David S. Miller457de432010-12-10 13:16:09 -08001847 *release_it = false;
David S. Millerdb3949c2010-12-02 11:52:07 -08001848 }
1849
1850 return peer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851}
1852
David S. Millerccb7c412010-12-01 18:09:13 -08001853static void *tcp_v6_tw_get_peer(struct sock *sk)
1854{
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001855 const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
1856 const struct inet_timewait_sock *tw = inet_twsk(sk);
David S. Millerccb7c412010-12-01 18:09:13 -08001857
1858 if (tw->tw_family == AF_INET)
1859 return tcp_v4_tw_get_peer(sk);
1860
David S. Millerdb3949c2010-12-02 11:52:07 -08001861 return inet_getpeer_v6(&tw6->tw_v6_daddr, 1);
David S. Millerccb7c412010-12-01 18:09:13 -08001862}
1863
1864static struct timewait_sock_ops tcp6_timewait_sock_ops = {
1865 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
1866 .twsk_unique = tcp_twsk_unique,
1867 .twsk_destructor= tcp_twsk_destructor,
1868 .twsk_getpeer = tcp_v6_tw_get_peer,
1869};
1870
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001871static const struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001872 .queue_xmit = inet6_csk_xmit,
1873 .send_check = tcp_v6_send_check,
1874 .rebuild_header = inet6_sk_rebuild_header,
1875 .conn_request = tcp_v6_conn_request,
1876 .syn_recv_sock = tcp_v6_syn_recv_sock,
David S. Miller3f419d22010-11-29 13:37:14 -08001877 .get_peer = tcp_v6_get_peer,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001878 .net_header_len = sizeof(struct ipv6hdr),
1879 .setsockopt = ipv6_setsockopt,
1880 .getsockopt = ipv6_getsockopt,
1881 .addr2sockaddr = inet6_csk_addr2sockaddr,
1882 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001883 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001884#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001885 .compat_setsockopt = compat_ipv6_setsockopt,
1886 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001887#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888};
1889
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001890#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001891static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001892 .md5_lookup = tcp_v6_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001893 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001894 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001895};
David S. Millera9286302006-11-14 19:53:22 -08001896#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898/*
1899 * TCP over IPv4 via INET6 API
1900 */
1901
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001902static const struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001903 .queue_xmit = ip_queue_xmit,
1904 .send_check = tcp_v4_send_check,
1905 .rebuild_header = inet_sk_rebuild_header,
1906 .conn_request = tcp_v6_conn_request,
1907 .syn_recv_sock = tcp_v6_syn_recv_sock,
David S. Miller3f419d22010-11-29 13:37:14 -08001908 .get_peer = tcp_v4_get_peer,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001909 .net_header_len = sizeof(struct iphdr),
1910 .setsockopt = ipv6_setsockopt,
1911 .getsockopt = ipv6_getsockopt,
1912 .addr2sockaddr = inet6_csk_addr2sockaddr,
1913 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001914 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001915#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001916 .compat_setsockopt = compat_ipv6_setsockopt,
1917 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001918#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919};
1920
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001921#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001922static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001923 .md5_lookup = tcp_v4_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001924 .calc_md5_hash = tcp_v4_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001925 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001926};
David S. Millera9286302006-11-14 19:53:22 -08001927#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929/* NOTE: A lot of things set to zero explicitly by call to
1930 * sk_alloc() so need not be done here.
1931 */
1932static int tcp_v6_init_sock(struct sock *sk)
1933{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001934 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 struct tcp_sock *tp = tcp_sk(sk);
1936
1937 skb_queue_head_init(&tp->out_of_order_queue);
1938 tcp_init_xmit_timers(sk);
1939 tcp_prequeue_init(tp);
1940
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001941 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 tp->mdev = TCP_TIMEOUT_INIT;
1943
1944 /* So many TCP implementations out there (incorrectly) count the
1945 * initial SYN frame in their delayed-ACK and congestion control
1946 * algorithms that we must have the following bandaid to talk
1947 * efficiently to them. -DaveM
1948 */
1949 tp->snd_cwnd = 2;
1950
1951 /* See draft-stevens-tcpca-spec-01 for discussion of the
1952 * initialization of these values.
1953 */
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07001954 tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 tp->snd_cwnd_clamp = ~0;
William Allen Simpsonbee7ca92009-11-10 09:51:18 +00001956 tp->mss_cache = TCP_MSS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
1958 tp->reordering = sysctl_tcp_reordering;
1959
1960 sk->sk_state = TCP_CLOSE;
1961
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001962 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001963 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001964 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 sk->sk_write_space = sk_stream_write_space;
1966 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1967
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001968#ifdef CONFIG_TCP_MD5SIG
1969 tp->af_specific = &tcp_sock_ipv6_specific;
1970#endif
1971
William Allen Simpson435cf552009-12-02 18:17:05 +00001972 /* TCP Cookie Transactions */
1973 if (sysctl_tcp_cookie_size > 0) {
1974 /* Default, cookies without s_data_payload. */
1975 tp->cookie_values =
1976 kzalloc(sizeof(*tp->cookie_values),
1977 sk->sk_allocation);
1978 if (tp->cookie_values != NULL)
1979 kref_init(&tp->cookie_values->kref);
1980 }
1981 /* Presumed zeroed, in order of appearance:
1982 * cookie_in_always, cookie_out_never,
1983 * s_data_constant, s_data_in, s_data_out
1984 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1986 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1987
Herbert Xueb4dea52008-12-29 23:04:08 -08001988 local_bh_disable();
Glauber Costad1a4c0b2011-12-11 21:47:04 +00001989 sock_update_memcg(sk);
Glauber Costa180d8cd2011-12-11 21:47:02 +00001990 sk_sockets_allocated_inc(sk);
Herbert Xueb4dea52008-12-29 23:04:08 -08001991 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993 return 0;
1994}
1995
Brian Haley7d06b2e2008-06-14 17:04:49 -07001996static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001998#ifdef CONFIG_TCP_MD5SIG
1999 /* Clean up the MD5 key list */
2000 if (tcp_sk(sk)->md5sig_info)
2001 tcp_v6_clear_md5_list(sk);
2002#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07002004 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005}
2006
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09002007#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002009static void get_openreq6(struct seq_file *seq,
Eric Dumazetcf533ea2011-10-21 05:22:42 -04002010 const struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 int ttd = req->expires - jiffies;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002013 const struct in6_addr *src = &inet6_rsk(req)->loc_addr;
2014 const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
2016 if (ttd < 0)
2017 ttd = 0;
2018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 seq_printf(seq,
2020 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00002021 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 i,
2023 src->s6_addr32[0], src->s6_addr32[1],
2024 src->s6_addr32[2], src->s6_addr32[3],
KOVACS Krisztianfd507032008-10-19 23:35:58 -07002025 ntohs(inet_rsk(req)->loc_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 dest->s6_addr32[0], dest->s6_addr32[1],
2027 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07002028 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 TCP_SYN_RECV,
2030 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002031 1, /* timers active (only the expire timer) */
2032 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 req->retrans,
2034 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002035 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 0, /* open_requests have no inode */
2037 0, req);
2038}
2039
2040static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
2041{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002042 const struct in6_addr *dest, *src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 __u16 destp, srcp;
2044 int timer_active;
2045 unsigned long timer_expires;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04002046 const struct inet_sock *inet = inet_sk(sp);
2047 const struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002048 const struct inet_connection_sock *icsk = inet_csk(sp);
Eric Dumazetcf533ea2011-10-21 05:22:42 -04002049 const struct ipv6_pinfo *np = inet6_sk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
2051 dest = &np->daddr;
2052 src = &np->rcv_saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +00002053 destp = ntohs(inet->inet_dport);
2054 srcp = ntohs(inet->inet_sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002055
2056 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002058 timer_expires = icsk->icsk_timeout;
2059 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002061 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 } else if (timer_pending(&sp->sk_timer)) {
2063 timer_active = 2;
2064 timer_expires = sp->sk_timer.expires;
2065 } else {
2066 timer_active = 0;
2067 timer_expires = jiffies;
2068 }
2069
2070 seq_printf(seq,
2071 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00002072 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 i,
2074 src->s6_addr32[0], src->s6_addr32[1],
2075 src->s6_addr32[2], src->s6_addr32[3], srcp,
2076 dest->s6_addr32[0], dest->s6_addr32[1],
2077 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002078 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07002079 tp->write_seq-tp->snd_una,
2080 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 timer_active,
2082 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002083 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03002085 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 sock_i_ino(sp),
2087 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07002088 jiffies_to_clock_t(icsk->icsk_rto),
2089 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002090 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07002091 tp->snd_cwnd,
2092 tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 );
2094}
2095
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002096static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07002097 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00002099 const struct in6_addr *dest, *src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 __u16 destp, srcp;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04002101 const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 int ttd = tw->tw_ttd - jiffies;
2103
2104 if (ttd < 0)
2105 ttd = 0;
2106
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002107 dest = &tw6->tw_v6_daddr;
2108 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 destp = ntohs(tw->tw_dport);
2110 srcp = ntohs(tw->tw_sport);
2111
2112 seq_printf(seq,
2113 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00002114 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 i,
2116 src->s6_addr32[0], src->s6_addr32[1],
2117 src->s6_addr32[2], src->s6_addr32[3], srcp,
2118 dest->s6_addr32[0], dest->s6_addr32[1],
2119 dest->s6_addr32[2], dest->s6_addr32[3], destp,
2120 tw->tw_substate, 0, 0,
2121 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
2122 atomic_read(&tw->tw_refcnt), tw);
2123}
2124
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125static int tcp6_seq_show(struct seq_file *seq, void *v)
2126{
2127 struct tcp_iter_state *st;
2128
2129 if (v == SEQ_START_TOKEN) {
2130 seq_puts(seq,
2131 " sl "
2132 "local_address "
2133 "remote_address "
2134 "st tx_queue rx_queue tr tm->when retrnsmt"
2135 " uid timeout inode\n");
2136 goto out;
2137 }
2138 st = seq->private;
2139
2140 switch (st->state) {
2141 case TCP_SEQ_STATE_LISTENING:
2142 case TCP_SEQ_STATE_ESTABLISHED:
2143 get_tcp6_sock(seq, v, st->num);
2144 break;
2145 case TCP_SEQ_STATE_OPENREQ:
2146 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
2147 break;
2148 case TCP_SEQ_STATE_TIME_WAIT:
2149 get_timewait6_sock(seq, v, st->num);
2150 break;
2151 }
2152out:
2153 return 0;
2154}
2155
Arjan van de Ven73cb88e2011-10-30 06:46:30 +00002156static const struct file_operations tcp6_afinfo_seq_fops = {
2157 .owner = THIS_MODULE,
2158 .open = tcp_seq_open,
2159 .read = seq_read,
2160 .llseek = seq_lseek,
2161 .release = seq_release_net
2162};
2163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 .name = "tcp6",
2166 .family = AF_INET6,
Arjan van de Ven73cb88e2011-10-30 06:46:30 +00002167 .seq_fops = &tcp6_afinfo_seq_fops,
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07002168 .seq_ops = {
2169 .show = tcp6_seq_show,
2170 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171};
2172
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002173int __net_init tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002175 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176}
2177
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002178void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002180 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181}
2182#endif
2183
2184struct proto tcpv6_prot = {
2185 .name = "TCPv6",
2186 .owner = THIS_MODULE,
2187 .close = tcp_close,
2188 .connect = tcp_v6_connect,
2189 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002190 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 .ioctl = tcp_ioctl,
2192 .init = tcp_v6_init_sock,
2193 .destroy = tcp_v6_destroy_sock,
2194 .shutdown = tcp_shutdown,
2195 .setsockopt = tcp_setsockopt,
2196 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 .recvmsg = tcp_recvmsg,
Changli Gao7ba42912010-07-10 20:41:55 +00002198 .sendmsg = tcp_sendmsg,
2199 .sendpage = tcp_sendpage,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 .backlog_rcv = tcp_v6_do_rcv,
2201 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08002202 .unhash = inet_unhash,
2203 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 .enter_memory_pressure = tcp_enter_memory_pressure,
2205 .sockets_allocated = &tcp_sockets_allocated,
2206 .memory_allocated = &tcp_memory_allocated,
2207 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002208 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 .sysctl_wmem = sysctl_tcp_wmem,
2210 .sysctl_rmem = sysctl_tcp_rmem,
2211 .max_header = MAX_TCP_HEADER,
2212 .obj_size = sizeof(struct tcp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08002213 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002214 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002215 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002216 .h.hashinfo = &tcp_hashinfo,
Changli Gao7ba42912010-07-10 20:41:55 +00002217 .no_autobind = true,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002218#ifdef CONFIG_COMPAT
2219 .compat_setsockopt = compat_tcp_setsockopt,
2220 .compat_getsockopt = compat_tcp_getsockopt,
2221#endif
Glauber Costad1a4c0b2011-12-11 21:47:04 +00002222#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
2223 .proto_cgroup = tcp_proto_cgroup,
2224#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225};
2226
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00002227static const struct inet6_protocol tcpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 .handler = tcp_v6_rcv,
2229 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002230 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002231 .gso_segment = tcp_tso_segment,
Herbert Xu684f2172009-01-08 10:41:23 -08002232 .gro_receive = tcp6_gro_receive,
2233 .gro_complete = tcp6_gro_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2235};
2236
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237static struct inet_protosw tcpv6_protosw = {
2238 .type = SOCK_STREAM,
2239 .protocol = IPPROTO_TCP,
2240 .prot = &tcpv6_prot,
2241 .ops = &inet6_stream_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002243 .flags = INET_PROTOSW_PERMANENT |
2244 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245};
2246
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002247static int __net_init tcpv6_net_init(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002248{
Denis V. Lunev56772422008-04-03 14:28:30 -07002249 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2250 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002251}
2252
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002253static void __net_exit tcpv6_net_exit(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002254{
Denis V. Lunev56772422008-04-03 14:28:30 -07002255 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002256}
2257
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002258static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002259{
2260 inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002261}
2262
2263static struct pernet_operations tcpv6_net_ops = {
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002264 .init = tcpv6_net_init,
2265 .exit = tcpv6_net_exit,
2266 .exit_batch = tcpv6_net_exit_batch,
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002267};
2268
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002269int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002271 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002272
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002273 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2274 if (ret)
2275 goto out;
2276
2277 /* register inet6 protocol */
2278 ret = inet6_register_protosw(&tcpv6_protosw);
2279 if (ret)
2280 goto out_tcpv6_protocol;
2281
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002282 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002283 if (ret)
2284 goto out_tcpv6_protosw;
2285out:
2286 return ret;
2287
2288out_tcpv6_protocol:
2289 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2290out_tcpv6_protosw:
2291 inet6_unregister_protosw(&tcpv6_protosw);
2292 goto out;
2293}
2294
Daniel Lezcano09f77092007-12-13 05:34:58 -08002295void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002296{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002297 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002298 inet6_unregister_protosw(&tcpv6_protosw);
2299 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300}