blob: 0302ec3fecfc01830903e17593a82e1dd0a814e9 [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 &&
David S. Miller81166dd2012-07-10 03:14:24 -0700280 ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr))
281 tcp_fetch_timewait_stamp(sk, dst);
David S. Miller493f3772010-12-02 12:14:29 -0800282
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800283 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800285 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
286 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
289
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000290 inet->inet_dport = usin->sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800293 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (err)
295 goto late_failure;
296
297 if (!tp->write_seq)
298 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
299 np->daddr.s6_addr32,
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000300 inet->inet_sport,
301 inet->inet_dport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 err = tcp_connect(sk);
304 if (err)
305 goto late_failure;
306
307 return 0;
308
309late_failure:
310 tcp_set_state(sk, TCP_CLOSE);
311 __sk_dst_reset(sk);
312failure:
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000313 inet->inet_dport = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 sk->sk_route_caps = 0;
315 return err;
316}
317
318static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700319 u8 type, u8 code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000321 const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300322 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 struct ipv6_pinfo *np;
324 struct sock *sk;
325 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900326 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 __u32 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700328 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700330 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800331 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700334 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
335 ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 return;
337 }
338
339 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700340 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 return;
342 }
343
344 bh_lock_sock(sk);
345 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700346 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 if (sk->sk_state == TCP_CLOSE)
349 goto out;
350
Stephen Hemmingere802af92010-04-22 15:24:53 -0700351 if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
352 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
353 goto out;
354 }
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900357 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (sk->sk_state != TCP_LISTEN &&
359 !between(seq, tp->snd_una, tp->snd_nxt)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700360 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 goto out;
362 }
363
364 np = inet6_sk(sk);
365
David S. Millerec18d9a2012-07-12 00:25:15 -0700366 if (type == NDISC_REDIRECT) {
367 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
368
David S. Miller1ed5c482012-07-12 00:41:25 -0700369 if (dst)
David S. Miller6700c272012-07-17 03:29:28 -0700370 dst->ops->redirect(dst, sk, skb);
David S. Millerec18d9a2012-07-12 00:25:15 -0700371 }
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 if (type == ICMPV6_PKT_TOOBIG) {
David S. Miller68d0c6d2011-03-01 13:19:07 -0800374 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 if (sock_owned_by_user(sk))
377 goto out;
378 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
379 goto out;
380
David S. Miller35ad9b92012-07-16 03:44:56 -0700381 dst = inet6_csk_update_pmtu(sk, ntohl(info));
382 if (!dst)
383 goto out;
David S. Miller81aded22012-06-15 14:54:11 -0700384
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800385 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 tcp_sync_mss(sk, dst_mtu(dst));
387 tcp_simple_retransmit(sk);
David S. Miller35ad9b92012-07-16 03:44:56 -0700388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 goto out;
390 }
391
392 icmpv6_err_convert(type, code, &err);
393
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700394 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700396 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 case TCP_LISTEN:
398 if (sock_owned_by_user(sk))
399 goto out;
400
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800401 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
402 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 if (!req)
404 goto out;
405
406 /* ICMPs are not backlogged, hence we cannot get
407 * an established socket here.
408 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700409 WARN_ON(req->sk != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700411 if (seq != tcp_rsk(req)->snt_isn) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700412 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 goto out;
414 }
415
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700416 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 goto out;
418
419 case TCP_SYN_SENT:
420 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900421 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 sk->sk_err = err;
424 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
425
426 tcp_done(sk);
427 } else
428 sk->sk_err_soft = err;
429 goto out;
430 }
431
432 if (!sock_owned_by_user(sk) && np->recverr) {
433 sk->sk_err = err;
434 sk->sk_error_report(sk);
435 } else
436 sk->sk_err_soft = err;
437
438out:
439 bh_unlock_sock(sk);
440 sock_put(sk);
441}
442
443
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000444static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
445 struct flowi6 *fl6,
Neal Cardwell3840a062012-06-28 12:34:19 +0000446 struct request_sock *req,
Eric Dumazetfff32692012-06-01 01:47:50 +0000447 struct request_values *rvp,
448 u16 queue_mapping)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800450 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct ipv6_pinfo *np = inet6_sk(sk);
452 struct sk_buff * skb;
Neal Cardwell94942182012-06-28 12:34:20 +0000453 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000455 /* First, grab a route. */
456 if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800457 goto done;
Neal Cardwell94942182012-06-28 12:34:20 +0000458
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000459 skb = tcp_make_synack(sk, dst, req, rvp);
Neal Cardwell94942182012-06-28 12:34:20 +0000460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (skb) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000462 __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000464 fl6->daddr = treq->rmt_addr;
Eric Dumazetfff32692012-06-01 01:47:50 +0000465 skb_set_queue_mapping(skb, queue_mapping);
RongQing.Li43264e02012-07-01 17:18:59 +0000466 err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200467 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
469
470done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 return err;
472}
473
Octavian Purdila72659ec2010-01-17 19:09:39 -0800474static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
475 struct request_values *rvp)
476{
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000477 struct flowi6 fl6;
478
Octavian Purdila72659ec2010-01-17 19:09:39 -0800479 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000480 return tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0);
Octavian Purdila72659ec2010-01-17 19:09:39 -0800481}
482
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700483static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Wei Yongjun800d55f2009-02-23 21:45:33 +0000485 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800488#ifdef CONFIG_TCP_MD5SIG
489static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000490 const struct in6_addr *addr)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800491{
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000492 return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800493}
494
495static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
496 struct sock *addr_sk)
497{
498 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
499}
500
501static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
502 struct request_sock *req)
503{
504 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
505}
506
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800507static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
508 int optlen)
509{
510 struct tcp_md5sig cmd;
511 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800512
513 if (optlen < sizeof(cmd))
514 return -EINVAL;
515
516 if (copy_from_user(&cmd, optval, sizeof(cmd)))
517 return -EFAULT;
518
519 if (sin6->sin6_family != AF_INET6)
520 return -EINVAL;
521
522 if (!cmd.tcpm_keylen) {
Brian Haleye773e4f2007-08-24 23:16:08 -0700523 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000524 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
525 AF_INET);
526 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
527 AF_INET6);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800528 }
529
530 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
531 return -EINVAL;
532
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000533 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
534 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
535 AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800536
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000537 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
538 AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800539}
540
Adam Langley49a72df2008-07-19 00:01:42 -0700541static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000542 const struct in6_addr *daddr,
543 const struct in6_addr *saddr, int nbytes)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800544{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800545 struct tcp6_pseudohdr *bp;
Adam Langley49a72df2008-07-19 00:01:42 -0700546 struct scatterlist sg;
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900547
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800548 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800549 /* 1. TCP pseudo-header (RFC2460) */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000550 bp->saddr = *saddr;
551 bp->daddr = *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700552 bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley00b13042008-07-31 21:36:07 -0700553 bp->len = cpu_to_be32(nbytes);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800554
Adam Langley49a72df2008-07-19 00:01:42 -0700555 sg_init_one(&sg, bp, sizeof(*bp));
556 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
557}
David S. Millerc7da57a2007-10-26 00:41:21 -0700558
Adam Langley49a72df2008-07-19 00:01:42 -0700559static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000560 const struct in6_addr *daddr, struct in6_addr *saddr,
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400561 const struct tcphdr *th)
Adam Langley49a72df2008-07-19 00:01:42 -0700562{
563 struct tcp_md5sig_pool *hp;
564 struct hash_desc *desc;
565
566 hp = tcp_get_md5sig_pool();
567 if (!hp)
568 goto clear_hash_noput;
569 desc = &hp->md5_desc;
570
571 if (crypto_hash_init(desc))
572 goto clear_hash;
573 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
574 goto clear_hash;
575 if (tcp_md5_hash_header(hp, th))
576 goto clear_hash;
577 if (tcp_md5_hash_key(hp, key))
578 goto clear_hash;
579 if (crypto_hash_final(desc, md5_hash))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800580 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800581
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800582 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800583 return 0;
Adam Langley49a72df2008-07-19 00:01:42 -0700584
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800585clear_hash:
586 tcp_put_md5sig_pool();
587clear_hash_noput:
588 memset(md5_hash, 0, 16);
Adam Langley49a72df2008-07-19 00:01:42 -0700589 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800590}
591
Adam Langley49a72df2008-07-19 00:01:42 -0700592static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400593 const struct sock *sk,
594 const struct request_sock *req,
595 const struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800596{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000597 const struct in6_addr *saddr, *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700598 struct tcp_md5sig_pool *hp;
599 struct hash_desc *desc;
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400600 const struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800601
602 if (sk) {
603 saddr = &inet6_sk(sk)->saddr;
604 daddr = &inet6_sk(sk)->daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700605 } else if (req) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800606 saddr = &inet6_rsk(req)->loc_addr;
607 daddr = &inet6_rsk(req)->rmt_addr;
Adam Langley49a72df2008-07-19 00:01:42 -0700608 } else {
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000609 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
Adam Langley49a72df2008-07-19 00:01:42 -0700610 saddr = &ip6h->saddr;
611 daddr = &ip6h->daddr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800612 }
Adam Langley49a72df2008-07-19 00:01:42 -0700613
614 hp = tcp_get_md5sig_pool();
615 if (!hp)
616 goto clear_hash_noput;
617 desc = &hp->md5_desc;
618
619 if (crypto_hash_init(desc))
620 goto clear_hash;
621
622 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
623 goto clear_hash;
624 if (tcp_md5_hash_header(hp, th))
625 goto clear_hash;
626 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
627 goto clear_hash;
628 if (tcp_md5_hash_key(hp, key))
629 goto clear_hash;
630 if (crypto_hash_final(desc, md5_hash))
631 goto clear_hash;
632
633 tcp_put_md5sig_pool();
634 return 0;
635
636clear_hash:
637 tcp_put_md5sig_pool();
638clear_hash_noput:
639 memset(md5_hash, 0, 16);
640 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800641}
642
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400643static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800644{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400645 const __u8 *hash_location = NULL;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800646 struct tcp_md5sig_key *hash_expected;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000647 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400648 const struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800649 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800650 u8 newhash[16];
651
652 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900653 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800654
David S. Miller785957d2008-07-30 03:03:15 -0700655 /* We've parsed the options - do we have a hash? */
656 if (!hash_expected && !hash_location)
657 return 0;
658
659 if (hash_expected && !hash_location) {
660 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800661 return 1;
662 }
663
David S. Miller785957d2008-07-30 03:03:15 -0700664 if (!hash_expected && hash_location) {
665 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800666 return 1;
667 }
668
669 /* check the signature */
Adam Langley49a72df2008-07-19 00:01:42 -0700670 genhash = tcp_v6_md5_hash_skb(newhash,
671 hash_expected,
672 NULL, NULL, skb);
673
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800674 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
Joe Perchese87cc472012-05-13 21:56:26 +0000675 net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
676 genhash ? "failed" : "mismatch",
677 &ip6h->saddr, ntohs(th->source),
678 &ip6h->daddr, ntohs(th->dest));
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800679 return 1;
680 }
681 return 0;
682}
683#endif
684
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800685struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700687 .obj_size = sizeof(struct tcp6_request_sock),
Octavian Purdila72659ec2010-01-17 19:09:39 -0800688 .rtx_syn_ack = tcp_v6_rtx_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700689 .send_ack = tcp_v6_reqsk_send_ack,
690 .destructor = tcp_v6_reqsk_destructor,
Octavian Purdila72659ec2010-01-17 19:09:39 -0800691 .send_reset = tcp_v6_send_reset,
692 .syn_ack_timeout = tcp_syn_ack_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693};
694
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800695#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +0000696static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800697 .md5_lookup = tcp_v6_reqsk_md5_lookup,
John Dykstrae3afe7b2009-07-16 05:04:51 +0000698 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800699};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800700#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800701
Herbert Xu8ad50d92010-04-11 02:15:54 +0000702static void __tcp_v6_send_check(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000703 const struct in6_addr *saddr, const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700705 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Patrick McHardy84fa7932006-08-29 16:44:56 -0700707 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000708 th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700709 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800710 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 } else {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000712 th->check = tcp_v6_check(skb->len, saddr, daddr,
713 csum_partial(th, th->doff << 2,
714 skb->csum));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716}
717
Herbert Xubb296242010-04-11 02:15:55 +0000718static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Herbert Xu8ad50d92010-04-11 02:15:54 +0000719{
720 struct ipv6_pinfo *np = inet6_sk(sk);
721
722 __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
723}
724
Herbert Xua430a432006-07-08 13:34:56 -0700725static int tcp_v6_gso_send_check(struct sk_buff *skb)
726{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000727 const struct ipv6hdr *ipv6h;
Herbert Xua430a432006-07-08 13:34:56 -0700728 struct tcphdr *th;
729
730 if (!pskb_may_pull(skb, sizeof(*th)))
731 return -EINVAL;
732
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700733 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700734 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700735
736 th->check = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -0700737 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xu8ad50d92010-04-11 02:15:54 +0000738 __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
Herbert Xua430a432006-07-08 13:34:56 -0700739 return 0;
740}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Herbert Xu36990672009-05-22 00:45:28 -0700742static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
743 struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800744{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000745 const struct ipv6hdr *iph = skb_gro_network_header(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800746
747 switch (skb->ip_summed) {
748 case CHECKSUM_COMPLETE:
Herbert Xu86911732009-01-29 14:19:50 +0000749 if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
Herbert Xu684f2172009-01-08 10:41:23 -0800750 skb->csum)) {
751 skb->ip_summed = CHECKSUM_UNNECESSARY;
752 break;
753 }
754
755 /* fall through */
756 case CHECKSUM_NONE:
757 NAPI_GRO_CB(skb)->flush = 1;
758 return NULL;
759 }
760
761 return tcp_gro_receive(head, skb);
762}
Herbert Xu684f2172009-01-08 10:41:23 -0800763
Herbert Xu36990672009-05-22 00:45:28 -0700764static int tcp6_gro_complete(struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800765{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000766 const struct ipv6hdr *iph = ipv6_hdr(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800767 struct tcphdr *th = tcp_hdr(skb);
768
769 th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
770 &iph->saddr, &iph->daddr, 0);
771 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
772
773 return tcp_gro_complete(skb);
774}
Herbert Xu684f2172009-01-08 10:41:23 -0800775
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700776static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
Eric Dumazetb903d322011-10-27 00:44:35 -0400777 u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400779 const struct tcphdr *th = tcp_hdr(skb);
780 struct tcphdr *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 struct sk_buff *buff;
David S. Miller4c9483b2011-03-12 16:22:43 -0500782 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000783 struct net *net = dev_net(skb_dst(skb)->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -0800784 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -0800785 unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazetadf30902009-06-02 05:19:30 +0000786 struct dst_entry *dst;
Al Viroe69a4adc2006-11-14 20:56:00 -0800787 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -0700790 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800791#ifdef CONFIG_TCP_MD5SIG
792 if (key)
793 tot_len += TCPOLEN_MD5SIG_ALIGNED;
794#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
797 GFP_ATOMIC);
798 if (buff == NULL)
799 return;
800
801 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
802
Ilpo Järvinen77c676d2008-10-09 14:41:38 -0700803 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Herbert Xu6651ffc2010-04-21 00:47:15 -0700804 skb_reset_transport_header(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 /* Swap the send and the receive. */
807 memset(t1, 0, sizeof(*t1));
808 t1->dest = th->source;
809 t1->source = th->dest;
Ilpo Järvinen77c676d2008-10-09 14:41:38 -0700810 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 t1->seq = htonl(seq);
812 t1->ack_seq = htonl(ack);
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700813 t1->ack = !rst || !th->ack;
814 t1->rst = rst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800816
Al Viroe69a4adc2006-11-14 20:56:00 -0800817 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800820 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
821 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
822 *topt++ = htonl(tcp_time_stamp);
Ilpo Järvinen53b12572008-10-08 14:36:33 -0700823 *topt++ = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800826#ifdef CONFIG_TCP_MD5SIG
827 if (key) {
828 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
829 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Adam Langley49a72df2008-07-19 00:01:42 -0700830 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
Adam Langley90b7e112008-07-31 20:49:48 -0700831 &ipv6_hdr(skb)->saddr,
832 &ipv6_hdr(skb)->daddr, t1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800833 }
834#endif
835
David S. Miller4c9483b2011-03-12 16:22:43 -0500836 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000837 fl6.daddr = ipv6_hdr(skb)->saddr;
838 fl6.saddr = ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
David S. Millere5700af2010-04-21 14:59:20 -0700840 buff->ip_summed = CHECKSUM_PARTIAL;
841 buff->csum = 0;
842
David S. Miller4c9483b2011-03-12 16:22:43 -0500843 __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
David S. Miller4c9483b2011-03-12 16:22:43 -0500845 fl6.flowi6_proto = IPPROTO_TCP;
846 fl6.flowi6_oif = inet6_iif(skb);
David S. Miller1958b852011-03-12 16:36:19 -0500847 fl6.fl6_dport = t1->dest;
848 fl6.fl6_sport = t1->source;
David S. Miller4c9483b2011-03-12 16:22:43 -0500849 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700851 /* Pass a socket to ip6_dst_lookup either it is for RST
852 * Underlying function will use this to retrieve the network
853 * namespace
854 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500855 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800856 if (!IS_ERR(dst)) {
857 skb_dst_set(buff, dst);
Eric Dumazetb903d322011-10-27 00:44:35 -0400858 ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800859 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
860 if (rst)
861 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
862 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 }
864
865 kfree_skb(buff);
866}
867
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700868static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
869{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400870 const struct tcphdr *th = tcp_hdr(skb);
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700871 u32 seq = 0, ack_seq = 0;
Guo-Fu Tsengfa3e5b42008-10-09 21:11:56 -0700872 struct tcp_md5sig_key *key = NULL;
Shawn Lu658ddaa2012-01-31 22:35:48 +0000873#ifdef CONFIG_TCP_MD5SIG
874 const __u8 *hash_location = NULL;
875 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
876 unsigned char newhash[16];
877 int genhash;
878 struct sock *sk1 = NULL;
879#endif
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700880
881 if (th->rst)
882 return;
883
884 if (!ipv6_unicast_destination(skb))
885 return;
886
887#ifdef CONFIG_TCP_MD5SIG
Shawn Lu658ddaa2012-01-31 22:35:48 +0000888 hash_location = tcp_parse_md5sig_option(th);
889 if (!sk && hash_location) {
890 /*
891 * active side is lost. Try to find listening socket through
892 * source port, and then find md5 key through listening socket.
893 * we are not loose security here:
894 * Incoming packet is checked with md5 hash with finding key,
895 * no RST generated if md5 hash doesn't match.
896 */
897 sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
898 &tcp_hashinfo, &ipv6h->daddr,
899 ntohs(th->source), inet6_iif(skb));
900 if (!sk1)
901 return;
902
903 rcu_read_lock();
904 key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr);
905 if (!key)
906 goto release_sk1;
907
908 genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb);
909 if (genhash || memcmp(hash_location, newhash, 16) != 0)
910 goto release_sk1;
911 } else {
912 key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL;
913 }
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700914#endif
915
916 if (th->ack)
917 seq = ntohl(th->ack_seq);
918 else
919 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
920 (th->doff << 2);
921
Eric Dumazetb903d322011-10-27 00:44:35 -0400922 tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0);
Shawn Lu658ddaa2012-01-31 22:35:48 +0000923
924#ifdef CONFIG_TCP_MD5SIG
925release_sk1:
926 if (sk1) {
927 rcu_read_unlock();
928 sock_put(sk1);
929 }
930#endif
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700931}
932
933static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
Eric Dumazetb903d322011-10-27 00:44:35 -0400934 struct tcp_md5sig_key *key, u8 tclass)
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700935{
Eric Dumazetb903d322011-10-27 00:44:35 -0400936 tcp_v6_send_response(skb, seq, ack, win, ts, key, 0, tclass);
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700937}
938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
940{
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700941 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800942 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +0900944 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700945 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
Eric Dumazetb903d322011-10-27 00:44:35 -0400946 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw),
947 tw->tw_tclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700949 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950}
951
Gui Jianfeng6edafaa2008-08-06 23:50:04 -0700952static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
953 struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +0900955 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 -0400956 tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957}
958
959
960static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
961{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700962 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700963 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 struct sock *nsk;
965
966 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800967 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700968 &ipv6_hdr(skb)->saddr,
969 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 if (req)
971 return tcp_check_req(sk, skb, req, prev);
972
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900973 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800974 &ipv6_hdr(skb)->saddr, th->source,
975 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 if (nsk) {
978 if (nsk->sk_state != TCP_TIME_WAIT) {
979 bh_lock_sock(nsk);
980 return nsk;
981 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700982 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return NULL;
984 }
985
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800986#ifdef CONFIG_SYN_COOKIES
Florian Westphalaf9b4732010-06-03 00:43:44 +0000987 if (!th->syn)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800988 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989#endif
990 return sk;
991}
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993/* FIXME: this is substantially similar to the ipv4 code.
994 * Can some kind of merge be done? -- erics
995 */
996static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
997{
William Allen Simpson4957faade2009-12-02 18:25:27 +0000998 struct tcp_extend_values tmp_ext;
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000999 struct tcp_options_received tmp_opt;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001000 const u8 *hash_location;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001001 struct request_sock *req;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001002 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 struct ipv6_pinfo *np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 struct tcp_sock *tp = tcp_sk(sk);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001005 __u32 isn = TCP_SKB_CB(skb)->when;
David S. Miller493f3772010-12-02 12:14:29 -08001006 struct dst_entry *dst = NULL;
Neal Cardwell3840a062012-06-28 12:34:19 +00001007 struct flowi6 fl6;
Eric Dumazeta2a385d2012-05-16 23:15:34 +00001008 bool want_cookie = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010 if (skb->protocol == htons(ETH_P_IP))
1011 return tcp_v4_conn_request(sk, skb);
1012
1013 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001014 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001016 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Eric Dumazet946cedc2011-08-30 03:21:44 +00001017 want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
1018 if (!want_cookie)
1019 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
1021
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001022 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 goto drop;
1024
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001025 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (req == NULL)
1027 goto drop;
1028
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001029#ifdef CONFIG_TCP_MD5SIG
1030 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1031#endif
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 tcp_clear_options(&tmp_opt);
1034 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1035 tmp_opt.user_mss = tp->rx_opt.user_mss;
Yuchung Cheng2100c8d2012-07-19 06:43:05 +00001036 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
William Allen Simpson4957faade2009-12-02 18:25:27 +00001038 if (tmp_opt.cookie_plus > 0 &&
1039 tmp_opt.saw_tstamp &&
1040 !tp->rx_opt.cookie_out_never &&
1041 (sysctl_tcp_cookie_size > 0 ||
1042 (tp->cookie_values != NULL &&
1043 tp->cookie_values->cookie_desired > 0))) {
1044 u8 *c;
1045 u32 *d;
1046 u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
1047 int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
1048
1049 if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
1050 goto drop_and_free;
1051
1052 /* Secret recipe starts with IP addresses */
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001053 d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
William Allen Simpson4957faade2009-12-02 18:25:27 +00001054 *mess++ ^= *d++;
1055 *mess++ ^= *d++;
1056 *mess++ ^= *d++;
1057 *mess++ ^= *d++;
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001058 d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
William Allen Simpson4957faade2009-12-02 18:25:27 +00001059 *mess++ ^= *d++;
1060 *mess++ ^= *d++;
1061 *mess++ ^= *d++;
1062 *mess++ ^= *d++;
1063
1064 /* plus variable length Initiator Cookie */
1065 c = (u8 *)mess;
1066 while (l-- > 0)
1067 *c++ ^= *hash_location++;
1068
Eric Dumazeta2a385d2012-05-16 23:15:34 +00001069 want_cookie = false; /* not our kind of cookie */
William Allen Simpson4957faade2009-12-02 18:25:27 +00001070 tmp_ext.cookie_out_never = 0; /* false */
1071 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1072 } else if (!tp->rx_opt.cookie_in_always) {
1073 /* redundant indications, but ensure initialization. */
1074 tmp_ext.cookie_out_never = 1; /* true */
1075 tmp_ext.cookie_plus = 0;
1076 } else {
1077 goto drop_and_free;
1078 }
1079 tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Florian Westphal4dfc2812008-04-10 03:12:40 -07001081 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001082 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1085 tcp_openreq_init(req, &tmp_opt, skb);
1086
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001087 treq = inet6_rsk(req);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001088 treq->rmt_addr = ipv6_hdr(skb)->saddr;
1089 treq->loc_addr = ipv6_hdr(skb)->daddr;
Florian Westphal172d69e2010-06-21 11:48:45 +00001090 if (!want_cookie || tmp_opt.tstamp_ok)
Eric Dumazetbd14b1b2012-05-04 05:14:02 +00001091 TCP_ECN_create_request(req, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Eric Dumazet4d0fe502011-11-23 17:29:23 -05001093 treq->iif = sk->sk_bound_dev_if;
1094
1095 /* So that link locals have meaning */
1096 if (!sk->sk_bound_dev_if &&
1097 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1098 treq->iif = inet6_iif(skb);
1099
Florian Westphal2bbdf382010-06-13 11:29:39 +00001100 if (!isn) {
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001101 if (ipv6_opt_accepted(sk, skb) ||
1102 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1103 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1104 atomic_inc(&skb->users);
1105 treq->pktopts = skb;
1106 }
David S. Miller493f3772010-12-02 12:14:29 -08001107
1108 if (want_cookie) {
Florian Westphal2bbdf382010-06-13 11:29:39 +00001109 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
1110 req->cookie_ts = tmp_opt.tstamp_ok;
David S. Miller493f3772010-12-02 12:14:29 -08001111 goto have_isn;
Florian Westphal2bbdf382010-06-13 11:29:39 +00001112 }
David S. Miller493f3772010-12-02 12:14:29 -08001113
1114 /* VJ's idea. We save last timestamp seen
1115 * from the destination in peer table, when entering
1116 * state TIME-WAIT, and check against it before
1117 * accepting new connection request.
1118 *
1119 * If "isn" is not zero, this request hit alive
1120 * timewait bucket, so that all the necessary checks
1121 * are made in the function processing timewait state.
1122 */
1123 if (tmp_opt.saw_tstamp &&
1124 tcp_death_row.sysctl_tw_recycle &&
David S. Miller81166dd2012-07-10 03:14:24 -07001125 (dst = inet6_csk_route_req(sk, &fl6, req)) != NULL) {
1126 if (!tcp_peer_is_proven(req, dst, true)) {
David S. Miller493f3772010-12-02 12:14:29 -08001127 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
1128 goto drop_and_release;
1129 }
1130 }
1131 /* Kill the following clause, if you dislike this way. */
1132 else if (!sysctl_tcp_syncookies &&
1133 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
1134 (sysctl_max_syn_backlog >> 2)) &&
David S. Miller81166dd2012-07-10 03:14:24 -07001135 !tcp_peer_is_proven(req, dst, false)) {
David S. Miller493f3772010-12-02 12:14:29 -08001136 /* Without syncookies last quarter of
1137 * backlog is filled with destinations,
1138 * proven to be alive.
1139 * It means that we continue to communicate
1140 * to destinations, already remembered
1141 * to the moment of synflood.
1142 */
1143 LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n",
1144 &treq->rmt_addr, ntohs(tcp_hdr(skb)->source));
1145 goto drop_and_release;
1146 }
1147
1148 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001149 }
David S. Miller493f3772010-12-02 12:14:29 -08001150have_isn:
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001151 tcp_rsk(req)->snt_isn = isn;
Jerry Chu9ad7c042011-06-08 11:08:38 +00001152 tcp_rsk(req)->snt_synack = tcp_time_stamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Neal Cardwell437c5b52012-06-23 19:22:00 +00001154 if (security_inet_conn_request(sk, skb, req))
1155 goto drop_and_release;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001156
Neal Cardwell9f10d3f2012-06-28 12:34:21 +00001157 if (tcp_v6_send_synack(sk, dst, &fl6, req,
Eric Dumazetfff32692012-06-01 01:47:50 +00001158 (struct request_values *)&tmp_ext,
1159 skb_get_queue_mapping(skb)) ||
William Allen Simpson4957faade2009-12-02 18:25:27 +00001160 want_cookie)
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001161 goto drop_and_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001163 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1164 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
David S. Miller493f3772010-12-02 12:14:29 -08001166drop_and_release:
1167 dst_release(dst);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001168drop_and_free:
1169 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170drop:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return 0; /* don't send reset */
1172}
1173
1174static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001175 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 struct dst_entry *dst)
1177{
Vegard Nossum78d15e82008-09-12 16:17:43 -07001178 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1180 struct tcp6_sock *newtcp6sk;
1181 struct inet_sock *newinet;
1182 struct tcp_sock *newtp;
1183 struct sock *newsk;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001184#ifdef CONFIG_TCP_MD5SIG
1185 struct tcp_md5sig_key *key;
1186#endif
Neal Cardwell3840a062012-06-28 12:34:19 +00001187 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189 if (skb->protocol == htons(ETH_P_IP)) {
1190 /*
1191 * v6 mapped
1192 */
1193
1194 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1195
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001196 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 return NULL;
1198
1199 newtcp6sk = (struct tcp6_sock *)newsk;
1200 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1201
1202 newinet = inet_sk(newsk);
1203 newnp = inet6_sk(newsk);
1204 newtp = tcp_sk(newsk);
1205
1206 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1207
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001208 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001210 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001212 newnp->rcv_saddr = newnp->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001214 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001216#ifdef CONFIG_TCP_MD5SIG
1217 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1218#endif
1219
Yan, Zheng676a1182011-09-25 02:21:30 +00001220 newnp->ipv6_ac_list = NULL;
1221 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 newnp->pktoptions = NULL;
1223 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001224 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001225 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Jiri Benc4c507d22012-02-09 09:35:49 +00001226 newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001228 /*
1229 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1230 * here, tcp_create_openreq_child now does this for us, see the comment in
1231 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001235 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 Sync it now.
1237 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001238 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
1240 return newsk;
1241 }
1242
Vegard Nossum78d15e82008-09-12 16:17:43 -07001243 treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 if (sk_acceptq_is_full(sk))
1246 goto out_overflow;
1247
David S. Miller493f3772010-12-02 12:14:29 -08001248 if (!dst) {
Neal Cardwell3840a062012-06-28 12:34:19 +00001249 dst = inet6_csk_route_req(sk, &fl6, req);
David S. Miller493f3772010-12-02 12:14:29 -08001250 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 newsk = tcp_create_openreq_child(sk, req, skb);
1255 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +02001256 goto out_nonewsk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001258 /*
1259 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1260 * count here, tcp_create_openreq_child now does this for us, see the
1261 * comment in that function for the gory details. -acme
1262 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Stephen Hemminger59eed272006-08-25 15:55:43 -07001264 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001265 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
1267 newtcp6sk = (struct tcp6_sock *)newsk;
1268 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1269
1270 newtp = tcp_sk(newsk);
1271 newinet = inet_sk(newsk);
1272 newnp = inet6_sk(newsk);
1273
1274 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1275
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001276 newnp->daddr = treq->rmt_addr;
1277 newnp->saddr = treq->loc_addr;
1278 newnp->rcv_saddr = treq->loc_addr;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001279 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001281 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
1283 First: no IPv4 options.
1284 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +00001285 newinet->inet_opt = NULL;
Yan, Zheng676a1182011-09-25 02:21:30 +00001286 newnp->ipv6_ac_list = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001287 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
1289 /* Clone RX bits */
1290 newnp->rxopt.all = np->rxopt.all;
1291
1292 /* Clone pktoptions received with SYN */
1293 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001294 if (treq->pktopts != NULL) {
1295 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
Eric Dumazetab185d72012-04-19 02:24:36 +00001296 consume_skb(treq->pktopts);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001297 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (newnp->pktoptions)
1299 skb_set_owner_r(newnp->pktoptions, newsk);
1300 }
1301 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001302 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001303 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Jiri Benc4c507d22012-02-09 09:35:49 +00001304 newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
1306 /* Clone native IPv6 options from listening socket (if any)
1307
1308 Yes, keeping reference count would be much more clever,
1309 but we make one more one thing there: reattach optmem
1310 to newsk.
1311 */
RongQing.Li43264e02012-07-01 17:18:59 +00001312 if (np->opt)
1313 newnp->opt = ipv6_dup_options(newsk, np->opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001315 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001317 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1318 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
John Heffner5d424d52006-03-20 17:53:41 -08001320 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 tcp_sync_mss(newsk, dst_mtu(dst));
David S. Miller0dbaee32010-12-13 12:52:14 -08001322 newtp->advmss = dst_metric_advmss(dst);
Neal Cardwelld135c522012-04-22 09:45:47 +00001323 if (tcp_sk(sk)->rx_opt.user_mss &&
1324 tcp_sk(sk)->rx_opt.user_mss < newtp->advmss)
1325 newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 tcp_initialize_rcv_mss(newsk);
Jerry Chu9ad7c042011-06-08 11:08:38 +00001328 if (tcp_rsk(req)->snt_synack)
1329 tcp_valid_rtt_meas(newsk,
1330 tcp_time_stamp - tcp_rsk(req)->snt_synack);
1331 newtp->total_retrans = req->retrans;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001333 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
1334 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001336#ifdef CONFIG_TCP_MD5SIG
1337 /* Copy over the MD5 key from the original socket */
1338 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1339 /* We're using one, so create a matching key
1340 * on the newsk structure. If we fail to get
1341 * memory, then we end up not copying the key
1342 * across. Shucks.
1343 */
Eric Dumazeta915da9b2012-01-31 05:18:33 +00001344 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newnp->daddr,
1345 AF_INET6, key->key, key->keylen, GFP_ATOMIC);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001346 }
1347#endif
1348
Balazs Scheidler093d2822010-10-21 13:06:43 +02001349 if (__inet_inherit_port(sk, newsk) < 0) {
1350 sock_put(newsk);
1351 goto out;
1352 }
Eric Dumazet9327f702009-12-04 03:46:54 +00001353 __inet6_hash(newsk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
1355 return newsk;
1356
1357out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001358 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001359out_nonewsk:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 dst_release(dst);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001361out:
1362 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 return NULL;
1364}
1365
Al Virob51655b2006-11-14 21:40:42 -08001366static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001368 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Herbert Xu684f2172009-01-08 10:41:23 -08001369 if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001370 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001371 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001375
Herbert Xu684f2172009-01-08 10:41:23 -08001376 skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001377 &ipv6_hdr(skb)->saddr,
1378 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001381 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 }
1383 return 0;
1384}
1385
1386/* The socket must have it's spinlock held when we get
1387 * here.
1388 *
1389 * We have a potential double-lock case here, so even when
1390 * doing backlog processing we use the BH locking scheme.
1391 * This is because we cannot sleep with the original spinlock
1392 * held.
1393 */
1394static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1395{
1396 struct ipv6_pinfo *np = inet6_sk(sk);
1397 struct tcp_sock *tp;
1398 struct sk_buff *opt_skb = NULL;
1399
1400 /* Imagine: socket is IPv6. IPv4 packet arrives,
1401 goes to IPv4 receive handler and backlogged.
1402 From backlog it always goes here. Kerboom...
1403 Fortunately, tcp_rcv_established and rcv_established
1404 handle them correctly, but it is not case with
1405 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1406 */
1407
1408 if (skb->protocol == htons(ETH_P_IP))
1409 return tcp_v4_do_rcv(sk, skb);
1410
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001411#ifdef CONFIG_TCP_MD5SIG
1412 if (tcp_v6_inbound_md5_hash (sk, skb))
1413 goto discard;
1414#endif
1415
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001416 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 goto discard;
1418
1419 /*
1420 * socket locking is here for SMP purposes as backlog rcv
1421 * is currently called with bh processing disabled.
1422 */
1423
1424 /* Do Stevens' IPV6_PKTOPTIONS.
1425
1426 Yes, guys, it is the only place in our code, where we
1427 may make it not affecting IPv4.
1428 The rest of code is protocol independent,
1429 and I do not like idea to uglify IPv4.
1430
1431 Actually, all the idea behind IPV6_PKTOPTIONS
1432 looks not very well thought. For now we latch
1433 options, received in the last packet, enqueued
1434 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001435 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 */
1437 if (np->rxopt.all)
1438 opt_skb = skb_clone(skb, GFP_ATOMIC);
1439
1440 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
Tom Herbertbdeab992011-08-14 19:45:55 +00001441 sock_rps_save_rxhash(sk, skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001442 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 goto reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 if (opt_skb)
1445 goto ipv6_pktoptions;
1446 return 0;
1447 }
1448
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001449 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 goto csum_err;
1451
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001452 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1454 if (!nsk)
1455 goto discard;
1456
1457 /*
1458 * Queue it on the new socket if the new socket is active,
1459 * otherwise we just shortcircuit this and continue with
1460 * the new socket..
1461 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001462 if(nsk != sk) {
Tom Herbertbdeab992011-08-14 19:45:55 +00001463 sock_rps_save_rxhash(nsk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 if (tcp_child_process(sk, nsk, skb))
1465 goto reset;
1466 if (opt_skb)
1467 __kfree_skb(opt_skb);
1468 return 0;
1469 }
Neil Horman47482f12011-04-06 13:07:09 -07001470 } else
Tom Herbertbdeab992011-08-14 19:45:55 +00001471 sock_rps_save_rxhash(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001473 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 goto reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 if (opt_skb)
1476 goto ipv6_pktoptions;
1477 return 0;
1478
1479reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001480 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481discard:
1482 if (opt_skb)
1483 __kfree_skb(opt_skb);
1484 kfree_skb(skb);
1485 return 0;
1486csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001487 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 goto discard;
1489
1490
1491ipv6_pktoptions:
1492 /* Do you ask, what is it?
1493
1494 1. skb was enqueued by tcp.
1495 2. skb is added to tail of read queue, rather than out of order.
1496 3. socket is not in passive state.
1497 4. Finally, it really contains options, which user wants to receive.
1498 */
1499 tp = tcp_sk(sk);
1500 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1501 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001502 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001503 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001504 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001505 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Jiri Benc4c507d22012-02-09 09:35:49 +00001506 if (np->rxopt.bits.rxtclass)
1507 np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if (ipv6_opt_accepted(sk, opt_skb)) {
1509 skb_set_owner_r(opt_skb, sk);
1510 opt_skb = xchg(&np->pktoptions, opt_skb);
1511 } else {
1512 __kfree_skb(opt_skb);
1513 opt_skb = xchg(&np->pktoptions, NULL);
1514 }
1515 }
1516
Wei Yongjun800d55f2009-02-23 21:45:33 +00001517 kfree_skb(opt_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 return 0;
1519}
1520
Herbert Xue5bbef22007-10-15 12:50:28 -07001521static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001523 const struct tcphdr *th;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001524 const struct ipv6hdr *hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 struct sock *sk;
1526 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001527 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
1529 if (skb->pkt_type != PACKET_HOST)
1530 goto discard_it;
1531
1532 /*
1533 * Count it even if it's bad.
1534 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001535 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1538 goto discard_it;
1539
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001540 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
1542 if (th->doff < sizeof(struct tcphdr)/4)
1543 goto bad_packet;
1544 if (!pskb_may_pull(skb, th->doff*4))
1545 goto discard_it;
1546
Herbert Xu60476372007-04-09 11:59:39 -07001547 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 goto bad_packet;
1549
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001550 th = tcp_hdr(skb);
Stephen Hemmingere802af92010-04-22 15:24:53 -07001551 hdr = ipv6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1553 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1554 skb->len - th->doff*4);
1555 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1556 TCP_SKB_CB(skb)->when = 0;
Eric Dumazetb82d1bb2011-09-27 02:20:08 -04001557 TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 TCP_SKB_CB(skb)->sacked = 0;
1559
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -07001560 sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 if (!sk)
1562 goto no_tcp_socket;
1563
1564process:
1565 if (sk->sk_state == TCP_TIME_WAIT)
1566 goto do_time_wait;
1567
Stephen Hemmingere802af92010-04-22 15:24:53 -07001568 if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) {
1569 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
1570 goto discard_and_relse;
1571 }
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1574 goto discard_and_relse;
1575
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001576 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 goto discard_and_relse;
1578
1579 skb->dev = NULL;
1580
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001581 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 ret = 0;
1583 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001584#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001585 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001586 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
Dave Jianga2bd1142012-04-04 16:10:46 -07001587 tp->ucopy.dma_chan = net_dma_find_channel();
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001588 if (tp->ucopy.dma_chan)
1589 ret = tcp_v6_do_rcv(sk, skb);
1590 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001591#endif
1592 {
1593 if (!tcp_prequeue(sk, skb))
1594 ret = tcp_v6_do_rcv(sk, skb);
1595 }
Eric Dumazetda882c12012-04-22 23:38:54 +00001596 } else if (unlikely(sk_add_backlog(sk, skb,
1597 sk->sk_rcvbuf + sk->sk_sndbuf))) {
Zhu Yi6b03a532010-03-04 18:01:41 +00001598 bh_unlock_sock(sk);
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001599 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
Zhu Yi6b03a532010-03-04 18:01:41 +00001600 goto discard_and_relse;
1601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 bh_unlock_sock(sk);
1603
1604 sock_put(sk);
1605 return ret ? -1 : 0;
1606
1607no_tcp_socket:
1608 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1609 goto discard_it;
1610
1611 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1612bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001613 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001615 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 }
1617
1618discard_it:
1619
1620 /*
1621 * Discard frame
1622 */
1623
1624 kfree_skb(skb);
1625 return 0;
1626
1627discard_and_relse:
1628 sock_put(sk);
1629 goto discard_it;
1630
1631do_time_wait:
1632 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001633 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 goto discard_it;
1635 }
1636
1637 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001638 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001639 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 goto discard_it;
1641 }
1642
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001643 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 case TCP_TW_SYN:
1645 {
1646 struct sock *sk2;
1647
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001648 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001649 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001650 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001652 struct inet_timewait_sock *tw = inet_twsk(sk);
1653 inet_twsk_deschedule(tw, &tcp_death_row);
1654 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 sk = sk2;
1656 goto process;
1657 }
1658 /* Fall through to ACK */
1659 }
1660 case TCP_TW_ACK:
1661 tcp_v6_timewait_ack(sk, skb);
1662 break;
1663 case TCP_TW_RST:
1664 goto no_tcp_socket;
1665 case TCP_TW_SUCCESS:;
1666 }
1667 goto discard_it;
1668}
1669
David S. Millerccb7c412010-12-01 18:09:13 -08001670static struct timewait_sock_ops tcp6_timewait_sock_ops = {
1671 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
1672 .twsk_unique = tcp_twsk_unique,
1673 .twsk_destructor= tcp_twsk_destructor,
David S. Millerccb7c412010-12-01 18:09:13 -08001674};
1675
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001676static const struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001677 .queue_xmit = inet6_csk_xmit,
1678 .send_check = tcp_v6_send_check,
1679 .rebuild_header = inet6_sk_rebuild_header,
1680 .conn_request = tcp_v6_conn_request,
1681 .syn_recv_sock = tcp_v6_syn_recv_sock,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001682 .net_header_len = sizeof(struct ipv6hdr),
Eric Dumazet67469602012-04-24 07:37:38 +00001683 .net_frag_header_len = sizeof(struct frag_hdr),
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001684 .setsockopt = ipv6_setsockopt,
1685 .getsockopt = ipv6_getsockopt,
1686 .addr2sockaddr = inet6_csk_addr2sockaddr,
1687 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001688 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001689#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001690 .compat_setsockopt = compat_ipv6_setsockopt,
1691 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001692#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693};
1694
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001695#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001696static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001697 .md5_lookup = tcp_v6_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001698 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001699 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001700};
David S. Millera9286302006-11-14 19:53:22 -08001701#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703/*
1704 * TCP over IPv4 via INET6 API
1705 */
1706
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001707static const struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001708 .queue_xmit = ip_queue_xmit,
1709 .send_check = tcp_v4_send_check,
1710 .rebuild_header = inet_sk_rebuild_header,
1711 .conn_request = tcp_v6_conn_request,
1712 .syn_recv_sock = tcp_v6_syn_recv_sock,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001713 .net_header_len = sizeof(struct iphdr),
1714 .setsockopt = ipv6_setsockopt,
1715 .getsockopt = ipv6_getsockopt,
1716 .addr2sockaddr = inet6_csk_addr2sockaddr,
1717 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001718 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001719#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001720 .compat_setsockopt = compat_ipv6_setsockopt,
1721 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001722#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723};
1724
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001725#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001726static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001727 .md5_lookup = tcp_v4_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001728 .calc_md5_hash = tcp_v4_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001729 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001730};
David S. Millera9286302006-11-14 19:53:22 -08001731#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733/* NOTE: A lot of things set to zero explicitly by call to
1734 * sk_alloc() so need not be done here.
1735 */
1736static int tcp_v6_init_sock(struct sock *sk)
1737{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001738 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
Neal Cardwell900f65d2012-04-19 09:55:21 +00001740 tcp_init_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001742 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001744#ifdef CONFIG_TCP_MD5SIG
David S. Millerac807fa2012-04-23 03:21:58 -04001745 tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001746#endif
1747
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 return 0;
1749}
1750
Brian Haley7d06b2e2008-06-14 17:04:49 -07001751static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001754 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755}
1756
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09001757#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001759static void get_openreq6(struct seq_file *seq,
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001760 const struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 int ttd = req->expires - jiffies;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001763 const struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1764 const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
1766 if (ttd < 0)
1767 ttd = 0;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 seq_printf(seq,
1770 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00001771 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 i,
1773 src->s6_addr32[0], src->s6_addr32[1],
1774 src->s6_addr32[2], src->s6_addr32[3],
KOVACS Krisztianfd507032008-10-19 23:35:58 -07001775 ntohs(inet_rsk(req)->loc_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 dest->s6_addr32[0], dest->s6_addr32[1],
1777 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001778 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 TCP_SYN_RECV,
1780 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001781 1, /* timers active (only the expire timer) */
1782 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 req->retrans,
1784 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001785 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 0, /* open_requests have no inode */
1787 0, req);
1788}
1789
1790static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1791{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001792 const struct in6_addr *dest, *src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 __u16 destp, srcp;
1794 int timer_active;
1795 unsigned long timer_expires;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001796 const struct inet_sock *inet = inet_sk(sp);
1797 const struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001798 const struct inet_connection_sock *icsk = inet_csk(sp);
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001799 const struct ipv6_pinfo *np = inet6_sk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
1801 dest = &np->daddr;
1802 src = &np->rcv_saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001803 destp = ntohs(inet->inet_dport);
1804 srcp = ntohs(inet->inet_sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001805
1806 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001808 timer_expires = icsk->icsk_timeout;
1809 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001811 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 } else if (timer_pending(&sp->sk_timer)) {
1813 timer_active = 2;
1814 timer_expires = sp->sk_timer.expires;
1815 } else {
1816 timer_active = 0;
1817 timer_expires = jiffies;
1818 }
1819
1820 seq_printf(seq,
1821 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00001822 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 i,
1824 src->s6_addr32[0], src->s6_addr32[1],
1825 src->s6_addr32[2], src->s6_addr32[3], srcp,
1826 dest->s6_addr32[0], dest->s6_addr32[1],
1827 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001828 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07001829 tp->write_seq-tp->snd_una,
1830 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 timer_active,
1832 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001833 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001835 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 sock_i_ino(sp),
1837 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07001838 jiffies_to_clock_t(icsk->icsk_rto),
1839 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001840 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07001841 tp->snd_cwnd,
1842 tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 );
1844}
1845
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001846static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001847 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001849 const struct in6_addr *dest, *src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 __u16 destp, srcp;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001851 const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 int ttd = tw->tw_ttd - jiffies;
1853
1854 if (ttd < 0)
1855 ttd = 0;
1856
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001857 dest = &tw6->tw_v6_daddr;
1858 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 destp = ntohs(tw->tw_dport);
1860 srcp = ntohs(tw->tw_sport);
1861
1862 seq_printf(seq,
1863 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00001864 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 i,
1866 src->s6_addr32[0], src->s6_addr32[1],
1867 src->s6_addr32[2], src->s6_addr32[3], srcp,
1868 dest->s6_addr32[0], dest->s6_addr32[1],
1869 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1870 tw->tw_substate, 0, 0,
1871 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1872 atomic_read(&tw->tw_refcnt), tw);
1873}
1874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875static int tcp6_seq_show(struct seq_file *seq, void *v)
1876{
1877 struct tcp_iter_state *st;
1878
1879 if (v == SEQ_START_TOKEN) {
1880 seq_puts(seq,
1881 " sl "
1882 "local_address "
1883 "remote_address "
1884 "st tx_queue rx_queue tr tm->when retrnsmt"
1885 " uid timeout inode\n");
1886 goto out;
1887 }
1888 st = seq->private;
1889
1890 switch (st->state) {
1891 case TCP_SEQ_STATE_LISTENING:
1892 case TCP_SEQ_STATE_ESTABLISHED:
1893 get_tcp6_sock(seq, v, st->num);
1894 break;
1895 case TCP_SEQ_STATE_OPENREQ:
1896 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
1897 break;
1898 case TCP_SEQ_STATE_TIME_WAIT:
1899 get_timewait6_sock(seq, v, st->num);
1900 break;
1901 }
1902out:
1903 return 0;
1904}
1905
Arjan van de Ven73cb88e2011-10-30 06:46:30 +00001906static const struct file_operations tcp6_afinfo_seq_fops = {
1907 .owner = THIS_MODULE,
1908 .open = tcp_seq_open,
1909 .read = seq_read,
1910 .llseek = seq_lseek,
1911 .release = seq_release_net
1912};
1913
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 .name = "tcp6",
1916 .family = AF_INET6,
Arjan van de Ven73cb88e2011-10-30 06:46:30 +00001917 .seq_fops = &tcp6_afinfo_seq_fops,
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07001918 .seq_ops = {
1919 .show = tcp6_seq_show,
1920 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921};
1922
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001923int __net_init tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07001925 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926}
1927
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07001928void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07001930 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931}
1932#endif
1933
1934struct proto tcpv6_prot = {
1935 .name = "TCPv6",
1936 .owner = THIS_MODULE,
1937 .close = tcp_close,
1938 .connect = tcp_v6_connect,
1939 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001940 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 .ioctl = tcp_ioctl,
1942 .init = tcp_v6_init_sock,
1943 .destroy = tcp_v6_destroy_sock,
1944 .shutdown = tcp_shutdown,
1945 .setsockopt = tcp_setsockopt,
1946 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 .recvmsg = tcp_recvmsg,
Changli Gao7ba42912010-07-10 20:41:55 +00001948 .sendmsg = tcp_sendmsg,
1949 .sendpage = tcp_sendpage,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 .backlog_rcv = tcp_v6_do_rcv,
Eric Dumazet46d3cea2012-07-11 05:50:31 +00001951 .release_cb = tcp_release_cb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001953 .unhash = inet_unhash,
1954 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 .enter_memory_pressure = tcp_enter_memory_pressure,
1956 .sockets_allocated = &tcp_sockets_allocated,
1957 .memory_allocated = &tcp_memory_allocated,
1958 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07001959 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 .sysctl_wmem = sysctl_tcp_wmem,
1961 .sysctl_rmem = sysctl_tcp_rmem,
1962 .max_header = MAX_TCP_HEADER,
1963 .obj_size = sizeof(struct tcp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08001964 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08001965 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001966 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07001967 .h.hashinfo = &tcp_hashinfo,
Changli Gao7ba42912010-07-10 20:41:55 +00001968 .no_autobind = true,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001969#ifdef CONFIG_COMPAT
1970 .compat_setsockopt = compat_tcp_setsockopt,
1971 .compat_getsockopt = compat_tcp_getsockopt,
1972#endif
Glauber Costad1a4c0b2011-12-11 21:47:04 +00001973#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
1974 .proto_cgroup = tcp_proto_cgroup,
1975#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976};
1977
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00001978static const struct inet6_protocol tcpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 .handler = tcp_v6_rcv,
1980 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07001981 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07001982 .gso_segment = tcp_tso_segment,
Herbert Xu684f2172009-01-08 10:41:23 -08001983 .gro_receive = tcp6_gro_receive,
1984 .gro_complete = tcp6_gro_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1986};
1987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988static struct inet_protosw tcpv6_protosw = {
1989 .type = SOCK_STREAM,
1990 .protocol = IPPROTO_TCP,
1991 .prot = &tcpv6_prot,
1992 .ops = &inet6_stream_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001994 .flags = INET_PROTOSW_PERMANENT |
1995 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996};
1997
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001998static int __net_init tcpv6_net_init(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08001999{
Denis V. Lunev56772422008-04-03 14:28:30 -07002000 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2001 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002002}
2003
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002004static void __net_exit tcpv6_net_exit(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002005{
Denis V. Lunev56772422008-04-03 14:28:30 -07002006 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002007}
2008
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002009static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002010{
2011 inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002012}
2013
2014static struct pernet_operations tcpv6_net_ops = {
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002015 .init = tcpv6_net_init,
2016 .exit = tcpv6_net_exit,
2017 .exit_batch = tcpv6_net_exit_batch,
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002018};
2019
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002020int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002022 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002023
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002024 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2025 if (ret)
2026 goto out;
2027
2028 /* register inet6 protocol */
2029 ret = inet6_register_protosw(&tcpv6_protosw);
2030 if (ret)
2031 goto out_tcpv6_protocol;
2032
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002033 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002034 if (ret)
2035 goto out_tcpv6_protosw;
2036out:
2037 return ret;
2038
2039out_tcpv6_protocol:
2040 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2041out_tcpv6_protosw:
2042 inet6_unregister_protosw(&tcpv6_protosw);
2043 goto out;
2044}
2045
Daniel Lezcano09f77092007-12-13 05:34:58 -08002046void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002047{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002048 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002049 inet6_unregister_protosw(&tcpv6_protosw);
2050 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051}