blob: 221224e72507cf462021c8ff330e355f067e7efb [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
Eric Dumazet563d34d2012-07-23 09:48:52 +0200318static void tcp_v6_mtu_reduced(struct sock *sk)
319{
320 struct dst_entry *dst;
321
322 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
323 return;
324
325 dst = inet6_csk_update_pmtu(sk, tcp_sk(sk)->mtu_info);
326 if (!dst)
327 return;
328
329 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
330 tcp_sync_mss(sk, dst_mtu(dst));
331 tcp_simple_retransmit(sk);
332 }
333}
334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700336 u8 type, u8 code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000338 const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300339 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 struct ipv6_pinfo *np;
341 struct sock *sk;
342 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900343 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 __u32 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700345 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700347 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800348 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700351 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
352 ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return;
354 }
355
356 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700357 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 return;
359 }
360
361 bh_lock_sock(sk);
Eric Dumazet563d34d2012-07-23 09:48:52 +0200362 if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG)
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700363 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 if (sk->sk_state == TCP_CLOSE)
366 goto out;
367
Stephen Hemmingere802af92010-04-22 15:24:53 -0700368 if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
369 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
370 goto out;
371 }
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900374 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 if (sk->sk_state != TCP_LISTEN &&
376 !between(seq, tp->snd_una, tp->snd_nxt)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700377 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 goto out;
379 }
380
381 np = inet6_sk(sk);
382
David S. Millerec18d9a2012-07-12 00:25:15 -0700383 if (type == NDISC_REDIRECT) {
384 struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
385
David S. Miller1ed5c482012-07-12 00:41:25 -0700386 if (dst)
David S. Miller6700c272012-07-17 03:29:28 -0700387 dst->ops->redirect(dst, sk, skb);
David S. Millerec18d9a2012-07-12 00:25:15 -0700388 }
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (type == ICMPV6_PKT_TOOBIG) {
Eric Dumazet563d34d2012-07-23 09:48:52 +0200391 tp->mtu_info = ntohl(info);
392 if (!sock_owned_by_user(sk))
393 tcp_v6_mtu_reduced(sk);
394 else
395 set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 goto out;
397 }
398
399 icmpv6_err_convert(type, code, &err);
400
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700401 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700403 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 case TCP_LISTEN:
405 if (sock_owned_by_user(sk))
406 goto out;
407
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800408 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
409 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (!req)
411 goto out;
412
413 /* ICMPs are not backlogged, hence we cannot get
414 * an established socket here.
415 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700416 WARN_ON(req->sk != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700418 if (seq != tcp_rsk(req)->snt_isn) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700419 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 goto out;
421 }
422
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700423 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 goto out;
425
426 case TCP_SYN_SENT:
427 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900428 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 sk->sk_err = err;
431 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
432
433 tcp_done(sk);
434 } else
435 sk->sk_err_soft = err;
436 goto out;
437 }
438
439 if (!sock_owned_by_user(sk) && np->recverr) {
440 sk->sk_err = err;
441 sk->sk_error_report(sk);
442 } else
443 sk->sk_err_soft = err;
444
445out:
446 bh_unlock_sock(sk);
447 sock_put(sk);
448}
449
450
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000451static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
452 struct flowi6 *fl6,
Neal Cardwell3840a062012-06-28 12:34:19 +0000453 struct request_sock *req,
Eric Dumazetfff32692012-06-01 01:47:50 +0000454 struct request_values *rvp,
455 u16 queue_mapping)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800457 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 struct ipv6_pinfo *np = inet6_sk(sk);
459 struct sk_buff * skb;
Neal Cardwell94942182012-06-28 12:34:20 +0000460 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000462 /* First, grab a route. */
463 if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800464 goto done;
Neal Cardwell94942182012-06-28 12:34:20 +0000465
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000466 skb = tcp_make_synack(sk, dst, req, rvp);
Neal Cardwell94942182012-06-28 12:34:20 +0000467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 if (skb) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000469 __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000471 fl6->daddr = treq->rmt_addr;
Eric Dumazetfff32692012-06-01 01:47:50 +0000472 skb_set_queue_mapping(skb, queue_mapping);
RongQing.Li43264e02012-07-01 17:18:59 +0000473 err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200474 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 }
476
477done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 return err;
479}
480
Octavian Purdila72659ec2010-01-17 19:09:39 -0800481static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
482 struct request_values *rvp)
483{
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000484 struct flowi6 fl6;
485
Octavian Purdila72659ec2010-01-17 19:09:39 -0800486 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
Neal Cardwell9f10d3f2012-06-28 12:34:21 +0000487 return tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0);
Octavian Purdila72659ec2010-01-17 19:09:39 -0800488}
489
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700490static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Wei Yongjun800d55f2009-02-23 21:45:33 +0000492 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493}
494
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800495#ifdef CONFIG_TCP_MD5SIG
496static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000497 const struct in6_addr *addr)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800498{
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000499 return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800500}
501
502static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
503 struct sock *addr_sk)
504{
505 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
506}
507
508static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
509 struct request_sock *req)
510{
511 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
512}
513
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800514static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
515 int optlen)
516{
517 struct tcp_md5sig cmd;
518 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800519
520 if (optlen < sizeof(cmd))
521 return -EINVAL;
522
523 if (copy_from_user(&cmd, optval, sizeof(cmd)))
524 return -EFAULT;
525
526 if (sin6->sin6_family != AF_INET6)
527 return -EINVAL;
528
529 if (!cmd.tcpm_keylen) {
Brian Haleye773e4f2007-08-24 23:16:08 -0700530 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000531 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
532 AF_INET);
533 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
534 AF_INET6);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800535 }
536
537 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
538 return -EINVAL;
539
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000540 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
541 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
542 AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800543
Eric Dumazeta915da9b2012-01-31 05:18:33 +0000544 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
545 AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800546}
547
Adam Langley49a72df2008-07-19 00:01:42 -0700548static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000549 const struct in6_addr *daddr,
550 const struct in6_addr *saddr, int nbytes)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800551{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800552 struct tcp6_pseudohdr *bp;
Adam Langley49a72df2008-07-19 00:01:42 -0700553 struct scatterlist sg;
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900554
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800555 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800556 /* 1. TCP pseudo-header (RFC2460) */
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000557 bp->saddr = *saddr;
558 bp->daddr = *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700559 bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley00b13042008-07-31 21:36:07 -0700560 bp->len = cpu_to_be32(nbytes);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800561
Adam Langley49a72df2008-07-19 00:01:42 -0700562 sg_init_one(&sg, bp, sizeof(*bp));
563 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
564}
David S. Millerc7da57a2007-10-26 00:41:21 -0700565
Adam Langley49a72df2008-07-19 00:01:42 -0700566static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000567 const struct in6_addr *daddr, struct in6_addr *saddr,
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400568 const struct tcphdr *th)
Adam Langley49a72df2008-07-19 00:01:42 -0700569{
570 struct tcp_md5sig_pool *hp;
571 struct hash_desc *desc;
572
573 hp = tcp_get_md5sig_pool();
574 if (!hp)
575 goto clear_hash_noput;
576 desc = &hp->md5_desc;
577
578 if (crypto_hash_init(desc))
579 goto clear_hash;
580 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
581 goto clear_hash;
582 if (tcp_md5_hash_header(hp, th))
583 goto clear_hash;
584 if (tcp_md5_hash_key(hp, key))
585 goto clear_hash;
586 if (crypto_hash_final(desc, md5_hash))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800587 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800588
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800589 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800590 return 0;
Adam Langley49a72df2008-07-19 00:01:42 -0700591
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800592clear_hash:
593 tcp_put_md5sig_pool();
594clear_hash_noput:
595 memset(md5_hash, 0, 16);
Adam Langley49a72df2008-07-19 00:01:42 -0700596 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800597}
598
Adam Langley49a72df2008-07-19 00:01:42 -0700599static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400600 const struct sock *sk,
601 const struct request_sock *req,
602 const struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800603{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000604 const struct in6_addr *saddr, *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700605 struct tcp_md5sig_pool *hp;
606 struct hash_desc *desc;
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400607 const struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800608
609 if (sk) {
610 saddr = &inet6_sk(sk)->saddr;
611 daddr = &inet6_sk(sk)->daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700612 } else if (req) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800613 saddr = &inet6_rsk(req)->loc_addr;
614 daddr = &inet6_rsk(req)->rmt_addr;
Adam Langley49a72df2008-07-19 00:01:42 -0700615 } else {
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000616 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
Adam Langley49a72df2008-07-19 00:01:42 -0700617 saddr = &ip6h->saddr;
618 daddr = &ip6h->daddr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800619 }
Adam Langley49a72df2008-07-19 00:01:42 -0700620
621 hp = tcp_get_md5sig_pool();
622 if (!hp)
623 goto clear_hash_noput;
624 desc = &hp->md5_desc;
625
626 if (crypto_hash_init(desc))
627 goto clear_hash;
628
629 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
630 goto clear_hash;
631 if (tcp_md5_hash_header(hp, th))
632 goto clear_hash;
633 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
634 goto clear_hash;
635 if (tcp_md5_hash_key(hp, key))
636 goto clear_hash;
637 if (crypto_hash_final(desc, md5_hash))
638 goto clear_hash;
639
640 tcp_put_md5sig_pool();
641 return 0;
642
643clear_hash:
644 tcp_put_md5sig_pool();
645clear_hash_noput:
646 memset(md5_hash, 0, 16);
647 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800648}
649
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400650static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800651{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400652 const __u8 *hash_location = NULL;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800653 struct tcp_md5sig_key *hash_expected;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000654 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
Eric Dumazet318cf7a2011-10-24 02:46:04 -0400655 const struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800656 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800657 u8 newhash[16];
658
659 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900660 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800661
David S. Miller785957d2008-07-30 03:03:15 -0700662 /* We've parsed the options - do we have a hash? */
663 if (!hash_expected && !hash_location)
664 return 0;
665
666 if (hash_expected && !hash_location) {
667 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800668 return 1;
669 }
670
David S. Miller785957d2008-07-30 03:03:15 -0700671 if (!hash_expected && hash_location) {
672 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800673 return 1;
674 }
675
676 /* check the signature */
Adam Langley49a72df2008-07-19 00:01:42 -0700677 genhash = tcp_v6_md5_hash_skb(newhash,
678 hash_expected,
679 NULL, NULL, skb);
680
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800681 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
Joe Perchese87cc472012-05-13 21:56:26 +0000682 net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
683 genhash ? "failed" : "mismatch",
684 &ip6h->saddr, ntohs(th->source),
685 &ip6h->daddr, ntohs(th->dest));
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800686 return 1;
687 }
688 return 0;
689}
690#endif
691
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800692struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700694 .obj_size = sizeof(struct tcp6_request_sock),
Octavian Purdila72659ec2010-01-17 19:09:39 -0800695 .rtx_syn_ack = tcp_v6_rtx_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700696 .send_ack = tcp_v6_reqsk_send_ack,
697 .destructor = tcp_v6_reqsk_destructor,
Octavian Purdila72659ec2010-01-17 19:09:39 -0800698 .send_reset = tcp_v6_send_reset,
699 .syn_ack_timeout = tcp_syn_ack_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700};
701
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800702#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +0000703static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800704 .md5_lookup = tcp_v6_reqsk_md5_lookup,
John Dykstrae3afe7b2009-07-16 05:04:51 +0000705 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800706};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800707#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800708
Herbert Xu8ad50d92010-04-11 02:15:54 +0000709static void __tcp_v6_send_check(struct sk_buff *skb,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000710 const struct in6_addr *saddr, const struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700712 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Patrick McHardy84fa7932006-08-29 16:44:56 -0700714 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000715 th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700716 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800717 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 } else {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000719 th->check = tcp_v6_check(skb->len, saddr, daddr,
720 csum_partial(th, th->doff << 2,
721 skb->csum));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 }
723}
724
Herbert Xubb296242010-04-11 02:15:55 +0000725static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Herbert Xu8ad50d92010-04-11 02:15:54 +0000726{
727 struct ipv6_pinfo *np = inet6_sk(sk);
728
729 __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
730}
731
Herbert Xua430a432006-07-08 13:34:56 -0700732static int tcp_v6_gso_send_check(struct sk_buff *skb)
733{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000734 const struct ipv6hdr *ipv6h;
Herbert Xua430a432006-07-08 13:34:56 -0700735 struct tcphdr *th;
736
737 if (!pskb_may_pull(skb, sizeof(*th)))
738 return -EINVAL;
739
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700740 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700741 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700742
743 th->check = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -0700744 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xu8ad50d92010-04-11 02:15:54 +0000745 __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
Herbert Xua430a432006-07-08 13:34:56 -0700746 return 0;
747}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Herbert Xu36990672009-05-22 00:45:28 -0700749static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
750 struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800751{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000752 const struct ipv6hdr *iph = skb_gro_network_header(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800753
754 switch (skb->ip_summed) {
755 case CHECKSUM_COMPLETE:
Herbert Xu86911732009-01-29 14:19:50 +0000756 if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
Herbert Xu684f2172009-01-08 10:41:23 -0800757 skb->csum)) {
758 skb->ip_summed = CHECKSUM_UNNECESSARY;
759 break;
760 }
761
762 /* fall through */
763 case CHECKSUM_NONE:
764 NAPI_GRO_CB(skb)->flush = 1;
765 return NULL;
766 }
767
768 return tcp_gro_receive(head, skb);
769}
Herbert Xu684f2172009-01-08 10:41:23 -0800770
Herbert Xu36990672009-05-22 00:45:28 -0700771static int tcp6_gro_complete(struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800772{
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000773 const struct ipv6hdr *iph = ipv6_hdr(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800774 struct tcphdr *th = tcp_hdr(skb);
775
776 th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
777 &iph->saddr, &iph->daddr, 0);
778 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
779
780 return tcp_gro_complete(skb);
781}
Herbert Xu684f2172009-01-08 10:41:23 -0800782
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700783static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
Eric Dumazetb903d322011-10-27 00:44:35 -0400784 u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400786 const struct tcphdr *th = tcp_hdr(skb);
787 struct tcphdr *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 struct sk_buff *buff;
David S. Miller4c9483b2011-03-12 16:22:43 -0500789 struct flowi6 fl6;
Eric Dumazetadf30902009-06-02 05:19:30 +0000790 struct net *net = dev_net(skb_dst(skb)->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -0800791 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -0800792 unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazetadf30902009-06-02 05:19:30 +0000793 struct dst_entry *dst;
Al Viroe69a4adc2006-11-14 20:56:00 -0800794 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -0700797 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800798#ifdef CONFIG_TCP_MD5SIG
799 if (key)
800 tot_len += TCPOLEN_MD5SIG_ALIGNED;
801#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
803 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
804 GFP_ATOMIC);
805 if (buff == NULL)
806 return;
807
808 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
809
Ilpo Järvinen77c676d2008-10-09 14:41:38 -0700810 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Herbert Xu6651ffc2010-04-21 00:47:15 -0700811 skb_reset_transport_header(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 /* Swap the send and the receive. */
814 memset(t1, 0, sizeof(*t1));
815 t1->dest = th->source;
816 t1->source = th->dest;
Ilpo Järvinen77c676d2008-10-09 14:41:38 -0700817 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 t1->seq = htonl(seq);
819 t1->ack_seq = htonl(ack);
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700820 t1->ack = !rst || !th->ack;
821 t1->rst = rst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800823
Al Viroe69a4adc2006-11-14 20:56:00 -0800824 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800827 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
828 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
829 *topt++ = htonl(tcp_time_stamp);
Ilpo Järvinen53b12572008-10-08 14:36:33 -0700830 *topt++ = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
832
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800833#ifdef CONFIG_TCP_MD5SIG
834 if (key) {
835 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
836 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Adam Langley49a72df2008-07-19 00:01:42 -0700837 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
Adam Langley90b7e112008-07-31 20:49:48 -0700838 &ipv6_hdr(skb)->saddr,
839 &ipv6_hdr(skb)->daddr, t1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800840 }
841#endif
842
David S. Miller4c9483b2011-03-12 16:22:43 -0500843 memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000844 fl6.daddr = ipv6_hdr(skb)->saddr;
845 fl6.saddr = ipv6_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
David S. Millere5700af2010-04-21 14:59:20 -0700847 buff->ip_summed = CHECKSUM_PARTIAL;
848 buff->csum = 0;
849
David S. Miller4c9483b2011-03-12 16:22:43 -0500850 __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
David S. Miller4c9483b2011-03-12 16:22:43 -0500852 fl6.flowi6_proto = IPPROTO_TCP;
853 fl6.flowi6_oif = inet6_iif(skb);
David S. Miller1958b852011-03-12 16:36:19 -0500854 fl6.fl6_dport = t1->dest;
855 fl6.fl6_sport = t1->source;
David S. Miller4c9483b2011-03-12 16:22:43 -0500856 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700858 /* Pass a socket to ip6_dst_lookup either it is for RST
859 * Underlying function will use this to retrieve the network
860 * namespace
861 */
David S. Miller4c9483b2011-03-12 16:22:43 -0500862 dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800863 if (!IS_ERR(dst)) {
864 skb_dst_set(buff, dst);
Eric Dumazetb903d322011-10-27 00:44:35 -0400865 ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
David S. Miller68d0c6d2011-03-01 13:19:07 -0800866 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
867 if (rst)
868 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
869 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
871
872 kfree_skb(buff);
873}
874
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700875static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
876{
Eric Dumazetcf533ea2011-10-21 05:22:42 -0400877 const struct tcphdr *th = tcp_hdr(skb);
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700878 u32 seq = 0, ack_seq = 0;
Guo-Fu Tsengfa3e5b42008-10-09 21:11:56 -0700879 struct tcp_md5sig_key *key = NULL;
Shawn Lu658ddaa2012-01-31 22:35:48 +0000880#ifdef CONFIG_TCP_MD5SIG
881 const __u8 *hash_location = NULL;
882 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
883 unsigned char newhash[16];
884 int genhash;
885 struct sock *sk1 = NULL;
886#endif
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700887
888 if (th->rst)
889 return;
890
891 if (!ipv6_unicast_destination(skb))
892 return;
893
894#ifdef CONFIG_TCP_MD5SIG
Shawn Lu658ddaa2012-01-31 22:35:48 +0000895 hash_location = tcp_parse_md5sig_option(th);
896 if (!sk && hash_location) {
897 /*
898 * active side is lost. Try to find listening socket through
899 * source port, and then find md5 key through listening socket.
900 * we are not loose security here:
901 * Incoming packet is checked with md5 hash with finding key,
902 * no RST generated if md5 hash doesn't match.
903 */
904 sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
905 &tcp_hashinfo, &ipv6h->daddr,
906 ntohs(th->source), inet6_iif(skb));
907 if (!sk1)
908 return;
909
910 rcu_read_lock();
911 key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr);
912 if (!key)
913 goto release_sk1;
914
915 genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb);
916 if (genhash || memcmp(hash_location, newhash, 16) != 0)
917 goto release_sk1;
918 } else {
919 key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL;
920 }
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700921#endif
922
923 if (th->ack)
924 seq = ntohl(th->ack_seq);
925 else
926 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
927 (th->doff << 2);
928
Eric Dumazetb903d322011-10-27 00:44:35 -0400929 tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0);
Shawn Lu658ddaa2012-01-31 22:35:48 +0000930
931#ifdef CONFIG_TCP_MD5SIG
932release_sk1:
933 if (sk1) {
934 rcu_read_unlock();
935 sock_put(sk1);
936 }
937#endif
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700938}
939
940static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
Eric Dumazetb903d322011-10-27 00:44:35 -0400941 struct tcp_md5sig_key *key, u8 tclass)
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700942{
Eric Dumazetb903d322011-10-27 00:44:35 -0400943 tcp_v6_send_response(skb, seq, ack, win, ts, key, 0, tclass);
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700944}
945
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
947{
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700948 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800949 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +0900951 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700952 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
Eric Dumazetb903d322011-10-27 00:44:35 -0400953 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw),
954 tw->tw_tclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700956 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957}
958
Gui Jianfeng6edafaa2008-08-06 23:50:04 -0700959static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
960 struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +0900962 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 -0400963 tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964}
965
966
967static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
968{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700969 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700970 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 struct sock *nsk;
972
973 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800974 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700975 &ipv6_hdr(skb)->saddr,
976 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (req)
978 return tcp_check_req(sk, skb, req, prev);
979
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900980 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800981 &ipv6_hdr(skb)->saddr, th->source,
982 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
984 if (nsk) {
985 if (nsk->sk_state != TCP_TIME_WAIT) {
986 bh_lock_sock(nsk);
987 return nsk;
988 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700989 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 return NULL;
991 }
992
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800993#ifdef CONFIG_SYN_COOKIES
Florian Westphalaf9b4732010-06-03 00:43:44 +0000994 if (!th->syn)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800995 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996#endif
997 return sk;
998}
999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000/* FIXME: this is substantially similar to the ipv4 code.
1001 * Can some kind of merge be done? -- erics
1002 */
1003static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1004{
William Allen Simpson4957faade2009-12-02 18:25:27 +00001005 struct tcp_extend_values tmp_ext;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001006 struct tcp_options_received tmp_opt;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001007 const u8 *hash_location;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001008 struct request_sock *req;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001009 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 struct ipv6_pinfo *np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 struct tcp_sock *tp = tcp_sk(sk);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001012 __u32 isn = TCP_SKB_CB(skb)->when;
David S. Miller493f3772010-12-02 12:14:29 -08001013 struct dst_entry *dst = NULL;
Neal Cardwell3840a062012-06-28 12:34:19 +00001014 struct flowi6 fl6;
Eric Dumazeta2a385d2012-05-16 23:15:34 +00001015 bool want_cookie = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
1017 if (skb->protocol == htons(ETH_P_IP))
1018 return tcp_v4_conn_request(sk, skb);
1019
1020 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001021 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001023 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Eric Dumazet946cedc2011-08-30 03:21:44 +00001024 want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
1025 if (!want_cookie)
1026 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 }
1028
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001029 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 goto drop;
1031
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001032 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 if (req == NULL)
1034 goto drop;
1035
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001036#ifdef CONFIG_TCP_MD5SIG
1037 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1038#endif
1039
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 tcp_clear_options(&tmp_opt);
1041 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1042 tmp_opt.user_mss = tp->rx_opt.user_mss;
Yuchung Cheng2100c8d2012-07-19 06:43:05 +00001043 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
William Allen Simpson4957faade2009-12-02 18:25:27 +00001045 if (tmp_opt.cookie_plus > 0 &&
1046 tmp_opt.saw_tstamp &&
1047 !tp->rx_opt.cookie_out_never &&
1048 (sysctl_tcp_cookie_size > 0 ||
1049 (tp->cookie_values != NULL &&
1050 tp->cookie_values->cookie_desired > 0))) {
1051 u8 *c;
1052 u32 *d;
1053 u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
1054 int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
1055
1056 if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
1057 goto drop_and_free;
1058
1059 /* Secret recipe starts with IP addresses */
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001060 d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
William Allen Simpson4957faade2009-12-02 18:25:27 +00001061 *mess++ ^= *d++;
1062 *mess++ ^= *d++;
1063 *mess++ ^= *d++;
1064 *mess++ ^= *d++;
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001065 d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
William Allen Simpson4957faade2009-12-02 18:25:27 +00001066 *mess++ ^= *d++;
1067 *mess++ ^= *d++;
1068 *mess++ ^= *d++;
1069 *mess++ ^= *d++;
1070
1071 /* plus variable length Initiator Cookie */
1072 c = (u8 *)mess;
1073 while (l-- > 0)
1074 *c++ ^= *hash_location++;
1075
Eric Dumazeta2a385d2012-05-16 23:15:34 +00001076 want_cookie = false; /* not our kind of cookie */
William Allen Simpson4957faade2009-12-02 18:25:27 +00001077 tmp_ext.cookie_out_never = 0; /* false */
1078 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1079 } else if (!tp->rx_opt.cookie_in_always) {
1080 /* redundant indications, but ensure initialization. */
1081 tmp_ext.cookie_out_never = 1; /* true */
1082 tmp_ext.cookie_plus = 0;
1083 } else {
1084 goto drop_and_free;
1085 }
1086 tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
Florian Westphal4dfc2812008-04-10 03:12:40 -07001088 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001089 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1092 tcp_openreq_init(req, &tmp_opt, skb);
1093
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001094 treq = inet6_rsk(req);
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001095 treq->rmt_addr = ipv6_hdr(skb)->saddr;
1096 treq->loc_addr = ipv6_hdr(skb)->daddr;
Florian Westphal172d69e2010-06-21 11:48:45 +00001097 if (!want_cookie || tmp_opt.tstamp_ok)
Eric Dumazetbd14b1b2012-05-04 05:14:02 +00001098 TCP_ECN_create_request(req, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
Eric Dumazet4d0fe502011-11-23 17:29:23 -05001100 treq->iif = sk->sk_bound_dev_if;
1101
1102 /* So that link locals have meaning */
1103 if (!sk->sk_bound_dev_if &&
1104 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1105 treq->iif = inet6_iif(skb);
1106
Florian Westphal2bbdf382010-06-13 11:29:39 +00001107 if (!isn) {
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001108 if (ipv6_opt_accepted(sk, skb) ||
1109 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1110 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1111 atomic_inc(&skb->users);
1112 treq->pktopts = skb;
1113 }
David S. Miller493f3772010-12-02 12:14:29 -08001114
1115 if (want_cookie) {
Florian Westphal2bbdf382010-06-13 11:29:39 +00001116 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
1117 req->cookie_ts = tmp_opt.tstamp_ok;
David S. Miller493f3772010-12-02 12:14:29 -08001118 goto have_isn;
Florian Westphal2bbdf382010-06-13 11:29:39 +00001119 }
David S. Miller493f3772010-12-02 12:14:29 -08001120
1121 /* VJ's idea. We save last timestamp seen
1122 * from the destination in peer table, when entering
1123 * state TIME-WAIT, and check against it before
1124 * accepting new connection request.
1125 *
1126 * If "isn" is not zero, this request hit alive
1127 * timewait bucket, so that all the necessary checks
1128 * are made in the function processing timewait state.
1129 */
1130 if (tmp_opt.saw_tstamp &&
1131 tcp_death_row.sysctl_tw_recycle &&
David S. Miller81166dd2012-07-10 03:14:24 -07001132 (dst = inet6_csk_route_req(sk, &fl6, req)) != NULL) {
1133 if (!tcp_peer_is_proven(req, dst, true)) {
David S. Miller493f3772010-12-02 12:14:29 -08001134 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
1135 goto drop_and_release;
1136 }
1137 }
1138 /* Kill the following clause, if you dislike this way. */
1139 else if (!sysctl_tcp_syncookies &&
1140 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
1141 (sysctl_max_syn_backlog >> 2)) &&
David S. Miller81166dd2012-07-10 03:14:24 -07001142 !tcp_peer_is_proven(req, dst, false)) {
David S. Miller493f3772010-12-02 12:14:29 -08001143 /* Without syncookies last quarter of
1144 * backlog is filled with destinations,
1145 * proven to be alive.
1146 * It means that we continue to communicate
1147 * to destinations, already remembered
1148 * to the moment of synflood.
1149 */
1150 LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n",
1151 &treq->rmt_addr, ntohs(tcp_hdr(skb)->source));
1152 goto drop_and_release;
1153 }
1154
1155 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001156 }
David S. Miller493f3772010-12-02 12:14:29 -08001157have_isn:
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001158 tcp_rsk(req)->snt_isn = isn;
Jerry Chu9ad7c042011-06-08 11:08:38 +00001159 tcp_rsk(req)->snt_synack = tcp_time_stamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Neal Cardwell437c5b52012-06-23 19:22:00 +00001161 if (security_inet_conn_request(sk, skb, req))
1162 goto drop_and_release;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001163
Neal Cardwell9f10d3f2012-06-28 12:34:21 +00001164 if (tcp_v6_send_synack(sk, dst, &fl6, req,
Eric Dumazetfff32692012-06-01 01:47:50 +00001165 (struct request_values *)&tmp_ext,
1166 skb_get_queue_mapping(skb)) ||
William Allen Simpson4957faade2009-12-02 18:25:27 +00001167 want_cookie)
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001168 goto drop_and_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001170 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1171 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
David S. Miller493f3772010-12-02 12:14:29 -08001173drop_and_release:
1174 dst_release(dst);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001175drop_and_free:
1176 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177drop:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 return 0; /* don't send reset */
1179}
1180
1181static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001182 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 struct dst_entry *dst)
1184{
Vegard Nossum78d15e82008-09-12 16:17:43 -07001185 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1187 struct tcp6_sock *newtcp6sk;
1188 struct inet_sock *newinet;
1189 struct tcp_sock *newtp;
1190 struct sock *newsk;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001191#ifdef CONFIG_TCP_MD5SIG
1192 struct tcp_md5sig_key *key;
1193#endif
Neal Cardwell3840a062012-06-28 12:34:19 +00001194 struct flowi6 fl6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196 if (skb->protocol == htons(ETH_P_IP)) {
1197 /*
1198 * v6 mapped
1199 */
1200
1201 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1202
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001203 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return NULL;
1205
1206 newtcp6sk = (struct tcp6_sock *)newsk;
1207 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1208
1209 newinet = inet_sk(newsk);
1210 newnp = inet6_sk(newsk);
1211 newtp = tcp_sk(newsk);
1212
1213 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1214
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001215 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001217 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001219 newnp->rcv_saddr = newnp->saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001221 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001223#ifdef CONFIG_TCP_MD5SIG
1224 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1225#endif
1226
Yan, Zheng676a1182011-09-25 02:21:30 +00001227 newnp->ipv6_ac_list = NULL;
1228 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 newnp->pktoptions = NULL;
1230 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001231 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001232 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Jiri Benc4c507d22012-02-09 09:35:49 +00001233 newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001235 /*
1236 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1237 * here, tcp_create_openreq_child now does this for us, see the comment in
1238 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001242 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 Sync it now.
1244 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001245 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 return newsk;
1248 }
1249
Vegard Nossum78d15e82008-09-12 16:17:43 -07001250 treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 if (sk_acceptq_is_full(sk))
1253 goto out_overflow;
1254
David S. Miller493f3772010-12-02 12:14:29 -08001255 if (!dst) {
Neal Cardwell3840a062012-06-28 12:34:19 +00001256 dst = inet6_csk_route_req(sk, &fl6, req);
David S. Miller493f3772010-12-02 12:14:29 -08001257 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 newsk = tcp_create_openreq_child(sk, req, skb);
1262 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +02001263 goto out_nonewsk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001265 /*
1266 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1267 * count here, tcp_create_openreq_child now does this for us, see the
1268 * comment in that function for the gory details. -acme
1269 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Stephen Hemminger59eed272006-08-25 15:55:43 -07001271 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001272 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
1274 newtcp6sk = (struct tcp6_sock *)newsk;
1275 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1276
1277 newtp = tcp_sk(newsk);
1278 newinet = inet_sk(newsk);
1279 newnp = inet6_sk(newsk);
1280
1281 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1282
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001283 newnp->daddr = treq->rmt_addr;
1284 newnp->saddr = treq->loc_addr;
1285 newnp->rcv_saddr = treq->loc_addr;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001286 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001288 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 First: no IPv4 options.
1291 */
Eric Dumazetf6d8bd02011-04-21 09:45:37 +00001292 newinet->inet_opt = NULL;
Yan, Zheng676a1182011-09-25 02:21:30 +00001293 newnp->ipv6_ac_list = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001294 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
1296 /* Clone RX bits */
1297 newnp->rxopt.all = np->rxopt.all;
1298
1299 /* Clone pktoptions received with SYN */
1300 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001301 if (treq->pktopts != NULL) {
1302 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
Eric Dumazetab185d72012-04-19 02:24:36 +00001303 consume_skb(treq->pktopts);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001304 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 if (newnp->pktoptions)
1306 skb_set_owner_r(newnp->pktoptions, newsk);
1307 }
1308 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001309 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001310 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Jiri Benc4c507d22012-02-09 09:35:49 +00001311 newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 /* Clone native IPv6 options from listening socket (if any)
1314
1315 Yes, keeping reference count would be much more clever,
1316 but we make one more one thing there: reattach optmem
1317 to newsk.
1318 */
RongQing.Li43264e02012-07-01 17:18:59 +00001319 if (np->opt)
1320 newnp->opt = ipv6_dup_options(newsk, np->opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001322 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001324 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1325 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
John Heffner5d424d52006-03-20 17:53:41 -08001327 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 tcp_sync_mss(newsk, dst_mtu(dst));
David S. Miller0dbaee32010-12-13 12:52:14 -08001329 newtp->advmss = dst_metric_advmss(dst);
Neal Cardwelld135c522012-04-22 09:45:47 +00001330 if (tcp_sk(sk)->rx_opt.user_mss &&
1331 tcp_sk(sk)->rx_opt.user_mss < newtp->advmss)
1332 newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
1333
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 tcp_initialize_rcv_mss(newsk);
Jerry Chu9ad7c042011-06-08 11:08:38 +00001335 if (tcp_rsk(req)->snt_synack)
1336 tcp_valid_rtt_meas(newsk,
1337 tcp_time_stamp - tcp_rsk(req)->snt_synack);
1338 newtp->total_retrans = req->retrans;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001340 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
1341 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001343#ifdef CONFIG_TCP_MD5SIG
1344 /* Copy over the MD5 key from the original socket */
1345 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1346 /* We're using one, so create a matching key
1347 * on the newsk structure. If we fail to get
1348 * memory, then we end up not copying the key
1349 * across. Shucks.
1350 */
Eric Dumazeta915da9b2012-01-31 05:18:33 +00001351 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newnp->daddr,
1352 AF_INET6, key->key, key->keylen, GFP_ATOMIC);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001353 }
1354#endif
1355
Balazs Scheidler093d2822010-10-21 13:06:43 +02001356 if (__inet_inherit_port(sk, newsk) < 0) {
1357 sock_put(newsk);
1358 goto out;
1359 }
Eric Dumazet9327f702009-12-04 03:46:54 +00001360 __inet6_hash(newsk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
1362 return newsk;
1363
1364out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001365 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001366out_nonewsk:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 dst_release(dst);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001368out:
1369 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 return NULL;
1371}
1372
Al Virob51655b2006-11-14 21:40:42 -08001373static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001375 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Herbert Xu684f2172009-01-08 10:41:23 -08001376 if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001377 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001378 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001382
Herbert Xu684f2172009-01-08 10:41:23 -08001383 skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001384 &ipv6_hdr(skb)->saddr,
1385 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001388 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 }
1390 return 0;
1391}
1392
1393/* The socket must have it's spinlock held when we get
1394 * here.
1395 *
1396 * We have a potential double-lock case here, so even when
1397 * doing backlog processing we use the BH locking scheme.
1398 * This is because we cannot sleep with the original spinlock
1399 * held.
1400 */
1401static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1402{
1403 struct ipv6_pinfo *np = inet6_sk(sk);
1404 struct tcp_sock *tp;
1405 struct sk_buff *opt_skb = NULL;
1406
1407 /* Imagine: socket is IPv6. IPv4 packet arrives,
1408 goes to IPv4 receive handler and backlogged.
1409 From backlog it always goes here. Kerboom...
1410 Fortunately, tcp_rcv_established and rcv_established
1411 handle them correctly, but it is not case with
1412 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1413 */
1414
1415 if (skb->protocol == htons(ETH_P_IP))
1416 return tcp_v4_do_rcv(sk, skb);
1417
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001418#ifdef CONFIG_TCP_MD5SIG
1419 if (tcp_v6_inbound_md5_hash (sk, skb))
1420 goto discard;
1421#endif
1422
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001423 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 goto discard;
1425
1426 /*
1427 * socket locking is here for SMP purposes as backlog rcv
1428 * is currently called with bh processing disabled.
1429 */
1430
1431 /* Do Stevens' IPV6_PKTOPTIONS.
1432
1433 Yes, guys, it is the only place in our code, where we
1434 may make it not affecting IPv4.
1435 The rest of code is protocol independent,
1436 and I do not like idea to uglify IPv4.
1437
1438 Actually, all the idea behind IPV6_PKTOPTIONS
1439 looks not very well thought. For now we latch
1440 options, received in the last packet, enqueued
1441 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001442 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 */
1444 if (np->rxopt.all)
1445 opt_skb = skb_clone(skb, GFP_ATOMIC);
1446
1447 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
Tom Herbertbdeab992011-08-14 19:45:55 +00001448 sock_rps_save_rxhash(sk, skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001449 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 goto reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 if (opt_skb)
1452 goto ipv6_pktoptions;
1453 return 0;
1454 }
1455
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001456 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 goto csum_err;
1458
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001459 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1461 if (!nsk)
1462 goto discard;
1463
1464 /*
1465 * Queue it on the new socket if the new socket is active,
1466 * otherwise we just shortcircuit this and continue with
1467 * the new socket..
1468 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001469 if(nsk != sk) {
Tom Herbertbdeab992011-08-14 19:45:55 +00001470 sock_rps_save_rxhash(nsk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 if (tcp_child_process(sk, nsk, skb))
1472 goto reset;
1473 if (opt_skb)
1474 __kfree_skb(opt_skb);
1475 return 0;
1476 }
Neil Horman47482f12011-04-06 13:07:09 -07001477 } else
Tom Herbertbdeab992011-08-14 19:45:55 +00001478 sock_rps_save_rxhash(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001480 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 goto reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 if (opt_skb)
1483 goto ipv6_pktoptions;
1484 return 0;
1485
1486reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001487 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488discard:
1489 if (opt_skb)
1490 __kfree_skb(opt_skb);
1491 kfree_skb(skb);
1492 return 0;
1493csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001494 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 goto discard;
1496
1497
1498ipv6_pktoptions:
1499 /* Do you ask, what is it?
1500
1501 1. skb was enqueued by tcp.
1502 2. skb is added to tail of read queue, rather than out of order.
1503 3. socket is not in passive state.
1504 4. Finally, it really contains options, which user wants to receive.
1505 */
1506 tp = tcp_sk(sk);
1507 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1508 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001509 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001510 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001511 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001512 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Jiri Benc4c507d22012-02-09 09:35:49 +00001513 if (np->rxopt.bits.rxtclass)
1514 np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 if (ipv6_opt_accepted(sk, opt_skb)) {
1516 skb_set_owner_r(opt_skb, sk);
1517 opt_skb = xchg(&np->pktoptions, opt_skb);
1518 } else {
1519 __kfree_skb(opt_skb);
1520 opt_skb = xchg(&np->pktoptions, NULL);
1521 }
1522 }
1523
Wei Yongjun800d55f2009-02-23 21:45:33 +00001524 kfree_skb(opt_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 return 0;
1526}
1527
Herbert Xue5bbef22007-10-15 12:50:28 -07001528static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529{
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001530 const struct tcphdr *th;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001531 const struct ipv6hdr *hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 struct sock *sk;
1533 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001534 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
1536 if (skb->pkt_type != PACKET_HOST)
1537 goto discard_it;
1538
1539 /*
1540 * Count it even if it's bad.
1541 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001542 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
1544 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1545 goto discard_it;
1546
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001547 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
1549 if (th->doff < sizeof(struct tcphdr)/4)
1550 goto bad_packet;
1551 if (!pskb_may_pull(skb, th->doff*4))
1552 goto discard_it;
1553
Herbert Xu60476372007-04-09 11:59:39 -07001554 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 goto bad_packet;
1556
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001557 th = tcp_hdr(skb);
Stephen Hemmingere802af92010-04-22 15:24:53 -07001558 hdr = ipv6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1560 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1561 skb->len - th->doff*4);
1562 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1563 TCP_SKB_CB(skb)->when = 0;
Eric Dumazetb82d1bb2011-09-27 02:20:08 -04001564 TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 TCP_SKB_CB(skb)->sacked = 0;
1566
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -07001567 sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 if (!sk)
1569 goto no_tcp_socket;
1570
1571process:
1572 if (sk->sk_state == TCP_TIME_WAIT)
1573 goto do_time_wait;
1574
Stephen Hemmingere802af92010-04-22 15:24:53 -07001575 if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) {
1576 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
1577 goto discard_and_relse;
1578 }
1579
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1581 goto discard_and_relse;
1582
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001583 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 goto discard_and_relse;
1585
1586 skb->dev = NULL;
1587
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001588 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 ret = 0;
1590 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001591#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001592 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001593 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
Dave Jianga2bd1142012-04-04 16:10:46 -07001594 tp->ucopy.dma_chan = net_dma_find_channel();
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001595 if (tp->ucopy.dma_chan)
1596 ret = tcp_v6_do_rcv(sk, skb);
1597 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001598#endif
1599 {
1600 if (!tcp_prequeue(sk, skb))
1601 ret = tcp_v6_do_rcv(sk, skb);
1602 }
Eric Dumazetda882c12012-04-22 23:38:54 +00001603 } else if (unlikely(sk_add_backlog(sk, skb,
1604 sk->sk_rcvbuf + sk->sk_sndbuf))) {
Zhu Yi6b03a532010-03-04 18:01:41 +00001605 bh_unlock_sock(sk);
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001606 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
Zhu Yi6b03a532010-03-04 18:01:41 +00001607 goto discard_and_relse;
1608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 bh_unlock_sock(sk);
1610
1611 sock_put(sk);
1612 return ret ? -1 : 0;
1613
1614no_tcp_socket:
1615 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1616 goto discard_it;
1617
1618 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1619bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001620 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001622 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 }
1624
1625discard_it:
1626
1627 /*
1628 * Discard frame
1629 */
1630
1631 kfree_skb(skb);
1632 return 0;
1633
1634discard_and_relse:
1635 sock_put(sk);
1636 goto discard_it;
1637
1638do_time_wait:
1639 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001640 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 goto discard_it;
1642 }
1643
1644 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001645 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001646 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 goto discard_it;
1648 }
1649
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001650 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 case TCP_TW_SYN:
1652 {
1653 struct sock *sk2;
1654
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001655 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001656 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001657 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001659 struct inet_timewait_sock *tw = inet_twsk(sk);
1660 inet_twsk_deschedule(tw, &tcp_death_row);
1661 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 sk = sk2;
1663 goto process;
1664 }
1665 /* Fall through to ACK */
1666 }
1667 case TCP_TW_ACK:
1668 tcp_v6_timewait_ack(sk, skb);
1669 break;
1670 case TCP_TW_RST:
1671 goto no_tcp_socket;
1672 case TCP_TW_SUCCESS:;
1673 }
1674 goto discard_it;
1675}
1676
Eric Dumazetc7109982012-07-26 12:18:11 +00001677static void tcp_v6_early_demux(struct sk_buff *skb)
1678{
1679 const struct ipv6hdr *hdr;
1680 const struct tcphdr *th;
1681 struct sock *sk;
1682
1683 if (skb->pkt_type != PACKET_HOST)
1684 return;
1685
1686 if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr)))
1687 return;
1688
1689 hdr = ipv6_hdr(skb);
1690 th = tcp_hdr(skb);
1691
1692 if (th->doff < sizeof(struct tcphdr) / 4)
1693 return;
1694
1695 sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
1696 &hdr->saddr, th->source,
1697 &hdr->daddr, ntohs(th->dest),
1698 inet6_iif(skb));
1699 if (sk) {
1700 skb->sk = sk;
1701 skb->destructor = sock_edemux;
1702 if (sk->sk_state != TCP_TIME_WAIT) {
1703 struct dst_entry *dst = sk->sk_rx_dst;
1704 struct inet_sock *icsk = inet_sk(sk);
1705 if (dst)
1706 dst = dst_check(dst, 0);
1707 if (dst &&
1708 icsk->rx_dst_ifindex == inet6_iif(skb))
1709 skb_dst_set_noref(skb, dst);
1710 }
1711 }
1712}
1713
David S. Millerccb7c412010-12-01 18:09:13 -08001714static struct timewait_sock_ops tcp6_timewait_sock_ops = {
1715 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
1716 .twsk_unique = tcp_twsk_unique,
1717 .twsk_destructor= tcp_twsk_destructor,
David S. Millerccb7c412010-12-01 18:09:13 -08001718};
1719
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001720static const struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001721 .queue_xmit = inet6_csk_xmit,
1722 .send_check = tcp_v6_send_check,
1723 .rebuild_header = inet6_sk_rebuild_header,
1724 .conn_request = tcp_v6_conn_request,
1725 .syn_recv_sock = tcp_v6_syn_recv_sock,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001726 .net_header_len = sizeof(struct ipv6hdr),
Eric Dumazet67469602012-04-24 07:37:38 +00001727 .net_frag_header_len = sizeof(struct frag_hdr),
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001728 .setsockopt = ipv6_setsockopt,
1729 .getsockopt = ipv6_getsockopt,
1730 .addr2sockaddr = inet6_csk_addr2sockaddr,
1731 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001732 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001733#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001734 .compat_setsockopt = compat_ipv6_setsockopt,
1735 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001736#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737};
1738
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001739#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001740static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001741 .md5_lookup = tcp_v6_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001742 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001743 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001744};
David S. Millera9286302006-11-14 19:53:22 -08001745#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001746
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747/*
1748 * TCP over IPv4 via INET6 API
1749 */
1750
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001751static const struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001752 .queue_xmit = ip_queue_xmit,
1753 .send_check = tcp_v4_send_check,
1754 .rebuild_header = inet_sk_rebuild_header,
1755 .conn_request = tcp_v6_conn_request,
1756 .syn_recv_sock = tcp_v6_syn_recv_sock,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001757 .net_header_len = sizeof(struct iphdr),
1758 .setsockopt = ipv6_setsockopt,
1759 .getsockopt = ipv6_getsockopt,
1760 .addr2sockaddr = inet6_csk_addr2sockaddr,
1761 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001762 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001763#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001764 .compat_setsockopt = compat_ipv6_setsockopt,
1765 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001766#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767};
1768
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001769#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3d2009-09-01 19:25:03 +00001770static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001771 .md5_lookup = tcp_v4_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001772 .calc_md5_hash = tcp_v4_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001773 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001774};
David S. Millera9286302006-11-14 19:53:22 -08001775#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777/* NOTE: A lot of things set to zero explicitly by call to
1778 * sk_alloc() so need not be done here.
1779 */
1780static int tcp_v6_init_sock(struct sock *sk)
1781{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001782 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
Neal Cardwell900f65d2012-04-19 09:55:21 +00001784 tcp_init_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001786 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001788#ifdef CONFIG_TCP_MD5SIG
David S. Millerac807fa2012-04-23 03:21:58 -04001789 tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001790#endif
1791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 return 0;
1793}
1794
Brian Haley7d06b2e2008-06-14 17:04:49 -07001795static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001798 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799}
1800
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09001801#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001803static void get_openreq6(struct seq_file *seq,
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001804 const struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 int ttd = req->expires - jiffies;
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001807 const struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1808 const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809
1810 if (ttd < 0)
1811 ttd = 0;
1812
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 seq_printf(seq,
1814 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00001815 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 i,
1817 src->s6_addr32[0], src->s6_addr32[1],
1818 src->s6_addr32[2], src->s6_addr32[3],
KOVACS Krisztianfd507032008-10-19 23:35:58 -07001819 ntohs(inet_rsk(req)->loc_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 dest->s6_addr32[0], dest->s6_addr32[1],
1821 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001822 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 TCP_SYN_RECV,
1824 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001825 1, /* timers active (only the expire timer) */
1826 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 req->retrans,
1828 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001829 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 0, /* open_requests have no inode */
1831 0, req);
1832}
1833
1834static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1835{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001836 const struct in6_addr *dest, *src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 __u16 destp, srcp;
1838 int timer_active;
1839 unsigned long timer_expires;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001840 const struct inet_sock *inet = inet_sk(sp);
1841 const struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001842 const struct inet_connection_sock *icsk = inet_csk(sp);
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001843 const struct ipv6_pinfo *np = inet6_sk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 dest = &np->daddr;
1846 src = &np->rcv_saddr;
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001847 destp = ntohs(inet->inet_dport);
1848 srcp = ntohs(inet->inet_sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001849
1850 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001852 timer_expires = icsk->icsk_timeout;
1853 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001855 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 } else if (timer_pending(&sp->sk_timer)) {
1857 timer_active = 2;
1858 timer_expires = sp->sk_timer.expires;
1859 } else {
1860 timer_active = 0;
1861 timer_expires = jiffies;
1862 }
1863
1864 seq_printf(seq,
1865 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00001866 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 i,
1868 src->s6_addr32[0], src->s6_addr32[1],
1869 src->s6_addr32[2], src->s6_addr32[3], srcp,
1870 dest->s6_addr32[0], dest->s6_addr32[1],
1871 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001872 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07001873 tp->write_seq-tp->snd_una,
1874 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 timer_active,
1876 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001877 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001879 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 sock_i_ino(sp),
1881 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07001882 jiffies_to_clock_t(icsk->icsk_rto),
1883 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001884 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07001885 tp->snd_cwnd,
1886 tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 );
1888}
1889
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001890static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001891 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892{
Eric Dumazetb71d1d42011-04-22 04:53:02 +00001893 const struct in6_addr *dest, *src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 __u16 destp, srcp;
Eric Dumazetcf533ea2011-10-21 05:22:42 -04001895 const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 int ttd = tw->tw_ttd - jiffies;
1897
1898 if (ttd < 0)
1899 ttd = 0;
1900
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001901 dest = &tw6->tw_v6_daddr;
1902 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 destp = ntohs(tw->tw_dport);
1904 srcp = ntohs(tw->tw_sport);
1905
1906 seq_printf(seq,
1907 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Dan Rosenberg71338aa2011-05-23 12:17:35 +00001908 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 i,
1910 src->s6_addr32[0], src->s6_addr32[1],
1911 src->s6_addr32[2], src->s6_addr32[3], srcp,
1912 dest->s6_addr32[0], dest->s6_addr32[1],
1913 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1914 tw->tw_substate, 0, 0,
1915 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1916 atomic_read(&tw->tw_refcnt), tw);
1917}
1918
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919static int tcp6_seq_show(struct seq_file *seq, void *v)
1920{
1921 struct tcp_iter_state *st;
1922
1923 if (v == SEQ_START_TOKEN) {
1924 seq_puts(seq,
1925 " sl "
1926 "local_address "
1927 "remote_address "
1928 "st tx_queue rx_queue tr tm->when retrnsmt"
1929 " uid timeout inode\n");
1930 goto out;
1931 }
1932 st = seq->private;
1933
1934 switch (st->state) {
1935 case TCP_SEQ_STATE_LISTENING:
1936 case TCP_SEQ_STATE_ESTABLISHED:
1937 get_tcp6_sock(seq, v, st->num);
1938 break;
1939 case TCP_SEQ_STATE_OPENREQ:
1940 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
1941 break;
1942 case TCP_SEQ_STATE_TIME_WAIT:
1943 get_timewait6_sock(seq, v, st->num);
1944 break;
1945 }
1946out:
1947 return 0;
1948}
1949
Arjan van de Ven73cb88e2011-10-30 06:46:30 +00001950static const struct file_operations tcp6_afinfo_seq_fops = {
1951 .owner = THIS_MODULE,
1952 .open = tcp_seq_open,
1953 .read = seq_read,
1954 .llseek = seq_lseek,
1955 .release = seq_release_net
1956};
1957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 .name = "tcp6",
1960 .family = AF_INET6,
Arjan van de Ven73cb88e2011-10-30 06:46:30 +00001961 .seq_fops = &tcp6_afinfo_seq_fops,
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07001962 .seq_ops = {
1963 .show = tcp6_seq_show,
1964 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965};
1966
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00001967int __net_init tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07001969 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970}
1971
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07001972void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07001974 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975}
1976#endif
1977
1978struct proto tcpv6_prot = {
1979 .name = "TCPv6",
1980 .owner = THIS_MODULE,
1981 .close = tcp_close,
1982 .connect = tcp_v6_connect,
1983 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001984 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 .ioctl = tcp_ioctl,
1986 .init = tcp_v6_init_sock,
1987 .destroy = tcp_v6_destroy_sock,
1988 .shutdown = tcp_shutdown,
1989 .setsockopt = tcp_setsockopt,
1990 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 .recvmsg = tcp_recvmsg,
Changli Gao7ba42912010-07-10 20:41:55 +00001992 .sendmsg = tcp_sendmsg,
1993 .sendpage = tcp_sendpage,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 .backlog_rcv = tcp_v6_do_rcv,
Eric Dumazet46d3cea2012-07-11 05:50:31 +00001995 .release_cb = tcp_release_cb,
Eric Dumazet563d34d2012-07-23 09:48:52 +02001996 .mtu_reduced = tcp_v6_mtu_reduced,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001998 .unhash = inet_unhash,
1999 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 .enter_memory_pressure = tcp_enter_memory_pressure,
2001 .sockets_allocated = &tcp_sockets_allocated,
2002 .memory_allocated = &tcp_memory_allocated,
2003 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002004 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 .sysctl_wmem = sysctl_tcp_wmem,
2006 .sysctl_rmem = sysctl_tcp_rmem,
2007 .max_header = MAX_TCP_HEADER,
2008 .obj_size = sizeof(struct tcp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08002009 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002010 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002011 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002012 .h.hashinfo = &tcp_hashinfo,
Changli Gao7ba42912010-07-10 20:41:55 +00002013 .no_autobind = true,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002014#ifdef CONFIG_COMPAT
2015 .compat_setsockopt = compat_tcp_setsockopt,
2016 .compat_getsockopt = compat_tcp_getsockopt,
2017#endif
Glauber Costad1a4c0b2011-12-11 21:47:04 +00002018#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
2019 .proto_cgroup = tcp_proto_cgroup,
2020#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021};
2022
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00002023static const struct inet6_protocol tcpv6_protocol = {
Eric Dumazetc7109982012-07-26 12:18:11 +00002024 .early_demux = tcp_v6_early_demux,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 .handler = tcp_v6_rcv,
2026 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002027 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002028 .gso_segment = tcp_tso_segment,
Herbert Xu684f2172009-01-08 10:41:23 -08002029 .gro_receive = tcp6_gro_receive,
2030 .gro_complete = tcp6_gro_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2032};
2033
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034static struct inet_protosw tcpv6_protosw = {
2035 .type = SOCK_STREAM,
2036 .protocol = IPPROTO_TCP,
2037 .prot = &tcpv6_prot,
2038 .ops = &inet6_stream_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002040 .flags = INET_PROTOSW_PERMANENT |
2041 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042};
2043
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002044static int __net_init tcpv6_net_init(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002045{
Denis V. Lunev56772422008-04-03 14:28:30 -07002046 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2047 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002048}
2049
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002050static void __net_exit tcpv6_net_exit(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002051{
Denis V. Lunev56772422008-04-03 14:28:30 -07002052 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002053}
2054
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002055static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002056{
2057 inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002058}
2059
2060static struct pernet_operations tcpv6_net_ops = {
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002061 .init = tcpv6_net_init,
2062 .exit = tcpv6_net_exit,
2063 .exit_batch = tcpv6_net_exit_batch,
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002064};
2065
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002066int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002068 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002069
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002070 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2071 if (ret)
2072 goto out;
2073
2074 /* register inet6 protocol */
2075 ret = inet6_register_protosw(&tcpv6_protosw);
2076 if (ret)
2077 goto out_tcpv6_protocol;
2078
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002079 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002080 if (ret)
2081 goto out_tcpv6_protosw;
2082out:
2083 return ret;
2084
2085out_tcpv6_protocol:
2086 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2087out_tcpv6_protosw:
2088 inet6_unregister_protosw(&tcpv6_protosw);
2089 goto out;
2090}
2091
Daniel Lezcano09f77092007-12-13 05:34:58 -08002092void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002093{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002094 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002095 inet6_unregister_protosw(&tcpv6_protosw);
2096 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097}