blob: 3895d91ea9fa146ef8b9c5b5ac674bb9daf242e3 [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
26#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/errno.h>
28#include <linux/types.h>
29#include <linux/socket.h>
30#include <linux/sockios.h>
31#include <linux/net.h>
32#include <linux/jiffies.h>
33#include <linux/in.h>
34#include <linux/in6.h>
35#include <linux/netdevice.h>
36#include <linux/init.h>
37#include <linux/jhash.h>
38#include <linux/ipsec.h>
39#include <linux/times.h>
40
41#include <linux/ipv6.h>
42#include <linux/icmpv6.h>
43#include <linux/random.h>
44
45#include <net/tcp.h>
46#include <net/ndisc.h>
Arnaldo Carvalho de Melo5324a042005-08-12 09:26:18 -030047#include <net/inet6_hashtables.h>
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -080048#include <net/inet6_connection_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/ipv6.h>
50#include <net/transp_v6.h>
51#include <net/addrconf.h>
52#include <net/ip6_route.h>
53#include <net/ip6_checksum.h>
54#include <net/inet_ecn.h>
55#include <net/protocol.h>
56#include <net/xfrm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <net/snmp.h>
58#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080059#include <net/timewait_sock.h>
Jeff Garzik18134be2007-10-26 22:53:14 -070060#include <net/netdma.h>
Denis V. Lunev3d58b5f2008-04-03 14:22:32 -070061#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63#include <asm/uaccess.h>
64
65#include <linux/proc_fs.h>
66#include <linux/seq_file.h>
67
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080068#include <linux/crypto.h>
69#include <linux/scatterlist.h>
70
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080071static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -070072static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080076static struct inet_connection_sock_af_ops ipv6_mapped;
77static struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080078#ifdef CONFIG_TCP_MD5SIG
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080079static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
80static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090081#else
82static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
83 struct in6_addr *addr)
84{
85 return NULL;
86}
David S. Millera9286302006-11-14 19:53:22 -080087#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static void tcp_v6_hash(struct sock *sk)
90{
91 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080092 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 tcp_prot.hash(sk);
94 return;
95 }
96 local_bh_disable();
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -080097 __inet6_hash(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 local_bh_enable();
99 }
100}
101
Al Viro868c86b2006-11-14 21:35:48 -0800102static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900103 struct in6_addr *saddr,
104 struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800105 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
107 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
108}
109
Gerrit Renkera94f7232006-11-10 14:06:49 -0800110static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700112 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
113 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700114 tcp_hdr(skb)->dest,
115 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116}
117
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900118static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 int addr_len)
120{
121 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900122 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800123 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 struct ipv6_pinfo *np = inet6_sk(sk);
125 struct tcp_sock *tp = tcp_sk(sk);
126 struct in6_addr *saddr = NULL, *final_p = NULL, final;
127 struct flowi fl;
128 struct dst_entry *dst;
129 int addr_type;
130 int err;
131
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900132 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 return -EINVAL;
134
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900135 if (usin->sin6_family != AF_INET6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 return(-EAFNOSUPPORT);
137
138 memset(&fl, 0, sizeof(fl));
139
140 if (np->sndflow) {
141 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
142 IP6_ECN_flow_init(fl.fl6_flowlabel);
143 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
144 struct ip6_flowlabel *flowlabel;
145 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
146 if (flowlabel == NULL)
147 return -EINVAL;
148 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
149 fl6_sock_release(flowlabel);
150 }
151 }
152
153 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900154 * connect() to INADDR_ANY means loopback (BSD'ism).
155 */
156
157 if(ipv6_addr_any(&usin->sin6_addr))
158 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160 addr_type = ipv6_addr_type(&usin->sin6_addr);
161
162 if(addr_type & IPV6_ADDR_MULTICAST)
163 return -ENETUNREACH;
164
165 if (addr_type&IPV6_ADDR_LINKLOCAL) {
166 if (addr_len >= sizeof(struct sockaddr_in6) &&
167 usin->sin6_scope_id) {
168 /* If interface is set while binding, indices
169 * must coincide.
170 */
171 if (sk->sk_bound_dev_if &&
172 sk->sk_bound_dev_if != usin->sin6_scope_id)
173 return -EINVAL;
174
175 sk->sk_bound_dev_if = usin->sin6_scope_id;
176 }
177
178 /* Connect to link-local address requires an interface */
179 if (!sk->sk_bound_dev_if)
180 return -EINVAL;
181 }
182
183 if (tp->rx_opt.ts_recent_stamp &&
184 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
185 tp->rx_opt.ts_recent = 0;
186 tp->rx_opt.ts_recent_stamp = 0;
187 tp->write_seq = 0;
188 }
189
190 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
191 np->flow_label = fl.fl6_flowlabel;
192
193 /*
194 * TCP over IPv4
195 */
196
197 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800198 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 struct sockaddr_in sin;
200
201 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
202
203 if (__ipv6_only_sock(sk))
204 return -ENETUNREACH;
205
206 sin.sin_family = AF_INET;
207 sin.sin_port = usin->sin6_port;
208 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
209
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800210 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800212#ifdef CONFIG_TCP_MD5SIG
213 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
214#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
217
218 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800219 icsk->icsk_ext_hdr_len = exthdrlen;
220 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800222#ifdef CONFIG_TCP_MD5SIG
223 tp->af_specific = &tcp_sock_ipv6_specific;
224#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 goto failure;
226 } else {
227 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
228 inet->saddr);
229 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
230 inet->rcv_saddr);
231 }
232
233 return err;
234 }
235
236 if (!ipv6_addr_any(&np->rcv_saddr))
237 saddr = &np->rcv_saddr;
238
239 fl.proto = IPPROTO_TCP;
240 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
241 ipv6_addr_copy(&fl.fl6_src,
242 (saddr ? saddr : &np->saddr));
243 fl.oif = sk->sk_bound_dev_if;
244 fl.fl_ip_dport = usin->sin6_port;
245 fl.fl_ip_sport = inet->sport;
246
247 if (np->opt && np->opt->srcrt) {
248 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
249 ipv6_addr_copy(&final, &fl.fl6_dst);
250 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
251 final_p = &final;
252 }
253
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700254 security_sk_classify_flow(sk, &fl);
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 err = ip6_dst_lookup(sk, &dst, &fl);
257 if (err)
258 goto failure;
259 if (final_p)
260 ipv6_addr_copy(&fl.fl6_dst, final_p);
261
Herbert Xubb728452007-12-12 18:48:58 -0800262 if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
David S. Miller14e50e52007-05-24 18:17:54 -0700263 if (err == -EREMOTE)
264 err = ip6_dst_blackhole(sk, &dst, &fl);
265 if (err < 0)
266 goto failure;
267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
269 if (saddr == NULL) {
270 saddr = &fl.fl6_src;
271 ipv6_addr_copy(&np->rcv_saddr, saddr);
272 }
273
274 /* set the source address */
275 ipv6_addr_copy(&np->saddr, saddr);
276 inet->rcv_saddr = LOOPBACK4_IPV6;
277
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700278 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700279 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800281 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800283 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
284 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
287
288 inet->dport = usin->sin6_port;
289
290 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800291 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 if (err)
293 goto late_failure;
294
295 if (!tp->write_seq)
296 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
297 np->daddr.s6_addr32,
298 inet->sport,
299 inet->dport);
300
301 err = tcp_connect(sk);
302 if (err)
303 goto late_failure;
304
305 return 0;
306
307late_failure:
308 tcp_set_state(sk, TCP_CLOSE);
309 __sk_dst_reset(sk);
310failure:
311 inet->dport = 0;
312 sk->sk_route_caps = 0;
313 return err;
314}
315
316static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Al Viro04ce6902006-11-08 00:21:01 -0800317 int type, int code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300320 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 struct ipv6_pinfo *np;
322 struct sock *sk;
323 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900324 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 __u32 seq;
326
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900327 sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800328 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 if (sk == NULL) {
331 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
332 return;
333 }
334
335 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700336 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 return;
338 }
339
340 bh_lock_sock(sk);
341 if (sock_owned_by_user(sk))
342 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
343
344 if (sk->sk_state == TCP_CLOSE)
345 goto out;
346
347 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900348 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 if (sk->sk_state != TCP_LISTEN &&
350 !between(seq, tp->snd_una, tp->snd_nxt)) {
351 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
352 goto out;
353 }
354
355 np = inet6_sk(sk);
356
357 if (type == ICMPV6_PKT_TOOBIG) {
358 struct dst_entry *dst = NULL;
359
360 if (sock_owned_by_user(sk))
361 goto out;
362 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
363 goto out;
364
365 /* icmp should have updated the destination cache entry */
366 dst = __sk_dst_check(sk, np->dst_cookie);
367
368 if (dst == NULL) {
369 struct inet_sock *inet = inet_sk(sk);
370 struct flowi fl;
371
372 /* BUGGG_FUTURE: Again, it is not clear how
373 to handle rthdr case. Ignore this complexity
374 for now.
375 */
376 memset(&fl, 0, sizeof(fl));
377 fl.proto = IPPROTO_TCP;
378 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
379 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
380 fl.oif = sk->sk_bound_dev_if;
381 fl.fl_ip_dport = inet->dport;
382 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700383 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
386 sk->sk_err_soft = -err;
387 goto out;
388 }
389
390 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
391 sk->sk_err_soft = -err;
392 goto out;
393 }
394
395 } else
396 dst_hold(dst);
397
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800398 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 tcp_sync_mss(sk, dst_mtu(dst));
400 tcp_simple_retransmit(sk);
401 } /* else let the usual retransmit timer handle it */
402 dst_release(dst);
403 goto out;
404 }
405
406 icmpv6_err_convert(type, code, &err);
407
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700408 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700410 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 case TCP_LISTEN:
412 if (sock_owned_by_user(sk))
413 goto out;
414
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800415 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
416 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (!req)
418 goto out;
419
420 /* ICMPs are not backlogged, hence we cannot get
421 * an established socket here.
422 */
423 BUG_TRAP(req->sk == NULL);
424
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700425 if (seq != tcp_rsk(req)->snt_isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
427 goto out;
428 }
429
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700430 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 goto out;
432
433 case TCP_SYN_SENT:
434 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900435 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 sk->sk_err = err;
438 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
439
440 tcp_done(sk);
441 } else
442 sk->sk_err_soft = err;
443 goto out;
444 }
445
446 if (!sock_owned_by_user(sk) && np->recverr) {
447 sk->sk_err = err;
448 sk->sk_error_report(sk);
449 } else
450 sk->sk_err_soft = err;
451
452out:
453 bh_unlock_sock(sk);
454 sock_put(sk);
455}
456
457
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800458static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800460 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 struct ipv6_pinfo *np = inet6_sk(sk);
462 struct sk_buff * skb;
463 struct ipv6_txoptions *opt = NULL;
464 struct in6_addr * final_p = NULL, final;
465 struct flowi fl;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800466 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 int err = -1;
468
469 memset(&fl, 0, sizeof(fl));
470 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700471 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
472 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700474 fl.oif = treq->iif;
475 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700477 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800479 opt = np->opt;
480 if (opt && opt->srcrt) {
481 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
482 ipv6_addr_copy(&final, &fl.fl6_dst);
483 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
484 final_p = &final;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
486
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800487 err = ip6_dst_lookup(sk, &dst, &fl);
488 if (err)
489 goto done;
490 if (final_p)
491 ipv6_addr_copy(&fl.fl6_dst, final_p);
492 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
493 goto done;
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 skb = tcp_make_synack(sk, dst, req);
496 if (skb) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700497 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 th->check = tcp_v6_check(th, skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700500 &treq->loc_addr, &treq->rmt_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 csum_partial((char *)th, skb->len, skb->csum));
502
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700503 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 err = ip6_xmit(sk, skb, &fl, opt, 0);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200505 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
507
508done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900509 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800511 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return err;
513}
514
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800515static inline void syn_flood_warning(struct sk_buff *skb)
516{
517#ifdef CONFIG_SYN_COOKIES
518 if (sysctl_tcp_syncookies)
519 printk(KERN_INFO
520 "TCPv6: Possible SYN flooding on port %d. "
521 "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
522 else
523#endif
524 printk(KERN_INFO
525 "TCPv6: Possible SYN flooding on port %d. "
526 "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
527}
528
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700529static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800531 if (inet6_rsk(req)->pktopts)
532 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533}
534
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800535#ifdef CONFIG_TCP_MD5SIG
536static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
537 struct in6_addr *addr)
538{
539 struct tcp_sock *tp = tcp_sk(sk);
540 int i;
541
542 BUG_ON(tp == NULL);
543
544 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
545 return NULL;
546
547 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900548 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
David S. Millerf8ab18d2007-09-28 15:18:35 -0700549 return &tp->md5sig_info->keys6[i].base;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800550 }
551 return NULL;
552}
553
554static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
555 struct sock *addr_sk)
556{
557 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
558}
559
560static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
561 struct request_sock *req)
562{
563 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
564}
565
566static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
567 char *newkey, u8 newkeylen)
568{
569 /* Add key to the list */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700570 struct tcp_md5sig_key *key;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800571 struct tcp_sock *tp = tcp_sk(sk);
572 struct tcp6_md5sig_key *keys;
573
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700574 key = tcp_v6_md5_do_lookup(sk, peer);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800575 if (key) {
576 /* modify existing entry - just update that one */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700577 kfree(key->key);
578 key->key = newkey;
579 key->keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800580 } else {
581 /* reallocate new list if current one is full. */
582 if (!tp->md5sig_info) {
583 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
584 if (!tp->md5sig_info) {
585 kfree(newkey);
586 return -ENOMEM;
587 }
David S. Miller3d7dbea2007-06-12 14:36:42 -0700588 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800589 }
YOSHIFUJI Hideakiaacbe8c2007-11-20 17:30:56 -0800590 if (tcp_alloc_md5sig_pool() == NULL) {
591 kfree(newkey);
592 return -ENOMEM;
593 }
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800594 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
595 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
596 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
597
598 if (!keys) {
599 tcp_free_md5sig_pool();
600 kfree(newkey);
601 return -ENOMEM;
602 }
603
604 if (tp->md5sig_info->entries6)
605 memmove(keys, tp->md5sig_info->keys6,
606 (sizeof (tp->md5sig_info->keys6[0]) *
607 tp->md5sig_info->entries6));
608
609 kfree(tp->md5sig_info->keys6);
610 tp->md5sig_info->keys6 = keys;
611 tp->md5sig_info->alloced6++;
612 }
613
614 ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
615 peer);
David S. Millerf8ab18d2007-09-28 15:18:35 -0700616 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
617 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800618
619 tp->md5sig_info->entries6++;
620 }
621 return 0;
622}
623
624static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
625 u8 *newkey, __u8 newkeylen)
626{
627 return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr,
628 newkey, newkeylen);
629}
630
631static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
632{
633 struct tcp_sock *tp = tcp_sk(sk);
634 int i;
635
636 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900637 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800638 /* Free the key */
David S. Millerf8ab18d2007-09-28 15:18:35 -0700639 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800640 tp->md5sig_info->entries6--;
641
642 if (tp->md5sig_info->entries6 == 0) {
643 kfree(tp->md5sig_info->keys6);
644 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700645 tp->md5sig_info->alloced6 = 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800646 } else {
647 /* shrink the database */
648 if (tp->md5sig_info->entries6 != i)
649 memmove(&tp->md5sig_info->keys6[i],
650 &tp->md5sig_info->keys6[i+1],
651 (tp->md5sig_info->entries6 - i)
652 * sizeof (tp->md5sig_info->keys6[0]));
653 }
YOSHIFUJI Hideaki77adefd2007-11-20 17:31:23 -0800654 tcp_free_md5sig_pool();
655 return 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800656 }
657 }
658 return -ENOENT;
659}
660
661static void tcp_v6_clear_md5_list (struct sock *sk)
662{
663 struct tcp_sock *tp = tcp_sk(sk);
664 int i;
665
666 if (tp->md5sig_info->entries6) {
667 for (i = 0; i < tp->md5sig_info->entries6; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700668 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800669 tp->md5sig_info->entries6 = 0;
670 tcp_free_md5sig_pool();
671 }
672
673 kfree(tp->md5sig_info->keys6);
674 tp->md5sig_info->keys6 = NULL;
675 tp->md5sig_info->alloced6 = 0;
676
677 if (tp->md5sig_info->entries4) {
678 for (i = 0; i < tp->md5sig_info->entries4; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700679 kfree(tp->md5sig_info->keys4[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800680 tp->md5sig_info->entries4 = 0;
681 tcp_free_md5sig_pool();
682 }
683
684 kfree(tp->md5sig_info->keys4);
685 tp->md5sig_info->keys4 = NULL;
686 tp->md5sig_info->alloced4 = 0;
687}
688
689static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
690 int optlen)
691{
692 struct tcp_md5sig cmd;
693 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
694 u8 *newkey;
695
696 if (optlen < sizeof(cmd))
697 return -EINVAL;
698
699 if (copy_from_user(&cmd, optval, sizeof(cmd)))
700 return -EFAULT;
701
702 if (sin6->sin6_family != AF_INET6)
703 return -EINVAL;
704
705 if (!cmd.tcpm_keylen) {
706 if (!tcp_sk(sk)->md5sig_info)
707 return -ENOENT;
Brian Haleye773e4f2007-08-24 23:16:08 -0700708 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800709 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
710 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
711 }
712
713 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
714 return -EINVAL;
715
716 if (!tcp_sk(sk)->md5sig_info) {
717 struct tcp_sock *tp = tcp_sk(sk);
718 struct tcp_md5sig_info *p;
719
720 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
721 if (!p)
722 return -ENOMEM;
723
724 tp->md5sig_info = p;
David S. Miller3d7dbea2007-06-12 14:36:42 -0700725 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800726 }
727
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200728 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800729 if (!newkey)
730 return -ENOMEM;
Brian Haleye773e4f2007-08-24 23:16:08 -0700731 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800732 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
733 newkey, cmd.tcpm_keylen);
734 }
735 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
736}
737
738static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
739 struct in6_addr *saddr,
740 struct in6_addr *daddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900741 struct tcphdr *th, unsigned int tcplen)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800742{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800743 struct tcp_md5sig_pool *hp;
744 struct tcp6_pseudohdr *bp;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800745 int err;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800746
747 hp = tcp_get_md5sig_pool();
748 if (!hp) {
Harvey Harrison0dc47872008-03-05 20:47:47 -0800749 printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800750 goto clear_hash_noput;
751 }
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900752
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800753 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800754
755 /* 1. TCP pseudo-header (RFC2460) */
756 ipv6_addr_copy(&bp->saddr, saddr);
757 ipv6_addr_copy(&bp->daddr, daddr);
758 bp->len = htonl(tcplen);
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900759 bp->protocol = htonl(IPPROTO_TCP);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800760
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900761 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
762 th, tcplen, hp);
David S. Millerc7da57a2007-10-26 00:41:21 -0700763
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900764 if (err)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800765 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800766
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900767 /* Free up the crypto pool */
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800768 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800769out:
770 return 0;
771clear_hash:
772 tcp_put_md5sig_pool();
773clear_hash_noput:
774 memset(md5_hash, 0, 16);
775 goto out;
776}
777
778static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
779 struct sock *sk,
780 struct dst_entry *dst,
781 struct request_sock *req,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900782 struct tcphdr *th, unsigned int tcplen)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800783{
784 struct in6_addr *saddr, *daddr;
785
786 if (sk) {
787 saddr = &inet6_sk(sk)->saddr;
788 daddr = &inet6_sk(sk)->daddr;
789 } else {
790 saddr = &inet6_rsk(req)->loc_addr;
791 daddr = &inet6_rsk(req)->rmt_addr;
792 }
793 return tcp_v6_do_calc_md5_hash(md5_hash, key,
794 saddr, daddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900795 th, tcplen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800796}
797
798static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
799{
800 __u8 *hash_location = NULL;
801 struct tcp_md5sig_key *hash_expected;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700802 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700803 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800804 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800805 u8 newhash[16];
806
807 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900808 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800809
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800810 /* do we have a hash as expected? */
811 if (!hash_expected) {
812 if (!hash_location)
813 return 0;
814 if (net_ratelimit()) {
815 printk(KERN_INFO "MD5 Hash NOT expected but found "
816 "(" NIP6_FMT ", %u)->"
817 "(" NIP6_FMT ", %u)\n",
818 NIP6(ip6h->saddr), ntohs(th->source),
819 NIP6(ip6h->daddr), ntohs(th->dest));
820 }
821 return 1;
822 }
823
824 if (!hash_location) {
825 if (net_ratelimit()) {
826 printk(KERN_INFO "MD5 Hash expected but NOT found "
827 "(" NIP6_FMT ", %u)->"
828 "(" NIP6_FMT ", %u)\n",
829 NIP6(ip6h->saddr), ntohs(th->source),
830 NIP6(ip6h->daddr), ntohs(th->dest));
831 }
832 return 1;
833 }
834
835 /* check the signature */
836 genhash = tcp_v6_do_calc_md5_hash(newhash,
837 hash_expected,
838 &ip6h->saddr, &ip6h->daddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900839 th, skb->len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800840 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
841 if (net_ratelimit()) {
842 printk(KERN_INFO "MD5 Hash %s for "
843 "(" NIP6_FMT ", %u)->"
844 "(" NIP6_FMT ", %u)\n",
845 genhash ? "failed" : "mismatch",
846 NIP6(ip6h->saddr), ntohs(th->source),
847 NIP6(ip6h->daddr), ntohs(th->dest));
848 }
849 return 1;
850 }
851 return 0;
852}
853#endif
854
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800855struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700857 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700859 .send_ack = tcp_v6_reqsk_send_ack,
860 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 .send_reset = tcp_v6_send_reset
862};
863
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800864#ifdef CONFIG_TCP_MD5SIG
Andrew Mortonb6332e62006-11-30 19:16:28 -0800865static struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800866 .md5_lookup = tcp_v6_reqsk_md5_lookup,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800867};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800868#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800869
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800870static struct timewait_sock_ops tcp6_timewait_sock_ops = {
871 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
872 .twsk_unique = tcp_twsk_unique,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800873 .twsk_destructor= tcp_twsk_destructor,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800874};
875
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800876static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700879 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Patrick McHardy84fa7932006-08-29 16:44:56 -0700881 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700883 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800884 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 } else {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900886 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
887 csum_partial((char *)th, th->doff<<2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 skb->csum));
889 }
890}
891
Herbert Xua430a432006-07-08 13:34:56 -0700892static int tcp_v6_gso_send_check(struct sk_buff *skb)
893{
894 struct ipv6hdr *ipv6h;
895 struct tcphdr *th;
896
897 if (!pskb_may_pull(skb, sizeof(*th)))
898 return -EINVAL;
899
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700900 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700901 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700902
903 th->check = 0;
904 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
905 IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700906 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800907 skb->csum_offset = offsetof(struct tcphdr, check);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700908 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xua430a432006-07-08 13:34:56 -0700909 return 0;
910}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800912static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700914 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 struct sk_buff *buff;
916 struct flowi fl;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900917 struct net *net = dev_net(skb->dst->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -0800918 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -0800919 unsigned int tot_len = sizeof(*th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800920#ifdef CONFIG_TCP_MD5SIG
921 struct tcp_md5sig_key *key;
922#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 if (th->rst)
925 return;
926
927 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900928 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800930#ifdef CONFIG_TCP_MD5SIG
931 if (sk)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700932 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800933 else
934 key = NULL;
935
936 if (key)
937 tot_len += TCPOLEN_MD5SIG_ALIGNED;
938#endif
939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /*
941 * We need to grab some memory, and put together an RST,
942 * and then put it into the queue to be sent.
943 */
944
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800945 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 GFP_ATOMIC);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900947 if (buff == NULL)
948 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800950 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800952 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 /* Swap the send and the receive. */
955 memset(t1, 0, sizeof(*t1));
956 t1->dest = th->source;
957 t1->source = th->dest;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800958 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 t1->rst = 1;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 if(th->ack) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900962 t1->seq = th->ack_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 } else {
964 t1->ack = 1;
965 t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
966 + skb->len - (th->doff<<2));
967 }
968
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800969#ifdef CONFIG_TCP_MD5SIG
970 if (key) {
Al Viro8e5200f2006-11-20 18:06:37 -0800971 __be32 *opt = (__be32*)(t1 + 1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800972 opt[0] = htonl((TCPOPT_NOP << 24) |
973 (TCPOPT_NOP << 16) |
974 (TCPOPT_MD5SIG << 8) |
975 TCPOLEN_MD5SIG);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700976 tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key,
977 &ipv6_hdr(skb)->daddr,
978 &ipv6_hdr(skb)->saddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900979 t1, tot_len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800980 }
981#endif
982
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
984
985 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700986 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
987 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
990 sizeof(*t1), IPPROTO_TCP,
991 buff->csum);
992
993 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300994 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 fl.fl_ip_dport = t1->dest;
996 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700997 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
Daniel Lezcanoc20121a2008-03-05 10:48:35 -0800999 /* Pass a socket to ip6_dst_lookup either it is for RST
1000 * Underlying function will use this to retrieve the network
1001 * namespace
1002 */
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001003 if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001005 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001006 ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001007 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
1008 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 }
1012
1013 kfree_skb(buff);
1014}
1015
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001016static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
1017 struct tcp_md5sig_key *key)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001019 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 struct sk_buff *buff;
1021 struct flowi fl;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001022 struct net *net = dev_net(skb->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001023 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -08001024 unsigned int tot_len = sizeof(struct tcphdr);
Al Viroe69a4adc2006-11-14 20:56:00 -08001025 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -07001028 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001029#ifdef CONFIG_TCP_MD5SIG
1030 if (key)
1031 tot_len += TCPOLEN_MD5SIG_ALIGNED;
1032#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
1035 GFP_ATOMIC);
1036 if (buff == NULL)
1037 return;
1038
1039 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
1040
1041 t1 = (struct tcphdr *) skb_push(buff,tot_len);
1042
1043 /* Swap the send and the receive. */
1044 memset(t1, 0, sizeof(*t1));
1045 t1->dest = th->source;
1046 t1->source = th->dest;
1047 t1->doff = tot_len/4;
1048 t1->seq = htonl(seq);
1049 t1->ack_seq = htonl(ack);
1050 t1->ack = 1;
1051 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001052
Al Viroe69a4adc2006-11-14 20:56:00 -08001053 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001056 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1057 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
1058 *topt++ = htonl(tcp_time_stamp);
1059 *topt = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
1061
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001062#ifdef CONFIG_TCP_MD5SIG
1063 if (key) {
1064 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1065 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001066 tcp_v6_do_calc_md5_hash((__u8 *)topt, key,
1067 &ipv6_hdr(skb)->daddr,
1068 &ipv6_hdr(skb)->saddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +09001069 t1, tot_len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001070 }
1071#endif
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 buff->csum = csum_partial((char *)t1, tot_len, 0);
1074
1075 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001076 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1077 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
1079 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
1080 tot_len, IPPROTO_TCP,
1081 buff->csum);
1082
1083 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001084 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 fl.fl_ip_dport = t1->dest;
1086 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001087 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001089 if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001090 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001091 ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001092 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096
1097 kfree_skb(buff);
1098}
1099
1100static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1101{
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001102 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001103 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001105 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001106 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001107 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001109 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110}
1111
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001112static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001114 tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
1115 tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116}
1117
1118
1119static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1120{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001121 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001122 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 struct sock *nsk;
1124
1125 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001126 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001127 &ipv6_hdr(skb)->saddr,
1128 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (req)
1130 return tcp_check_req(sk, skb, req, prev);
1131
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001132 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001133 &ipv6_hdr(skb)->saddr, th->source,
1134 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136 if (nsk) {
1137 if (nsk->sk_state != TCP_TIME_WAIT) {
1138 bh_lock_sock(nsk);
1139 return nsk;
1140 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001141 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 return NULL;
1143 }
1144
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001145#ifdef CONFIG_SYN_COOKIES
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (!th->rst && !th->syn && th->ack)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001147 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148#endif
1149 return sk;
1150}
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152/* FIXME: this is substantially similar to the ipv4 code.
1153 * Can some kind of merge be done? -- erics
1154 */
1155static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1156{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001157 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 struct ipv6_pinfo *np = inet6_sk(sk);
1159 struct tcp_options_received tmp_opt;
1160 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001161 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 __u32 isn = TCP_SKB_CB(skb)->when;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001163#ifdef CONFIG_SYN_COOKIES
1164 int want_cookie = 0;
1165#else
1166#define want_cookie 0
1167#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 if (skb->protocol == htons(ETH_P_IP))
1170 return tcp_v4_conn_request(sk, skb);
1171
1172 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001173 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001175 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (net_ratelimit())
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001177 syn_flood_warning(skb);
1178#ifdef CONFIG_SYN_COOKIES
1179 if (sysctl_tcp_syncookies)
1180 want_cookie = 1;
1181 else
1182#endif
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001183 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
1185
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001186 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 goto drop;
1188
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001189 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 if (req == NULL)
1191 goto drop;
1192
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001193#ifdef CONFIG_TCP_MD5SIG
1194 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1195#endif
1196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 tcp_clear_options(&tmp_opt);
1198 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1199 tmp_opt.user_mss = tp->rx_opt.user_mss;
1200
1201 tcp_parse_options(skb, &tmp_opt, 0);
1202
Florian Westphal4dfc2812008-04-10 03:12:40 -07001203 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001204 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1207 tcp_openreq_init(req, &tmp_opt, skb);
1208
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001209 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001210 ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
1211 ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001212 if (!want_cookie)
1213 TCP_ECN_create_request(req, tcp_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001215 if (want_cookie) {
1216 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
Florian Westphal4dfc2812008-04-10 03:12:40 -07001217 req->cookie_ts = tmp_opt.tstamp_ok;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001218 } else if (!isn) {
1219 if (ipv6_opt_accepted(sk, skb) ||
1220 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1221 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1222 atomic_inc(&skb->users);
1223 treq->pktopts = skb;
1224 }
1225 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001227 /* So that link locals have meaning */
1228 if (!sk->sk_bound_dev_if &&
1229 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1230 treq->iif = inet6_iif(skb);
1231
Gerrit Renkera94f7232006-11-10 14:06:49 -08001232 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001235 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001237 security_inet_conn_request(sk, skb, req);
1238
Denis V. Lunevfd80eb92008-02-29 11:43:03 -08001239 if (tcp_v6_send_synack(sk, req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 goto drop;
1241
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001242 if (!want_cookie) {
1243 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1244 return 0;
1245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247drop:
1248 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001249 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 return 0; /* don't send reset */
1252}
1253
1254static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001255 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 struct dst_entry *dst)
1257{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001258 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1260 struct tcp6_sock *newtcp6sk;
1261 struct inet_sock *newinet;
1262 struct tcp_sock *newtp;
1263 struct sock *newsk;
1264 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001265#ifdef CONFIG_TCP_MD5SIG
1266 struct tcp_md5sig_key *key;
1267#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269 if (skb->protocol == htons(ETH_P_IP)) {
1270 /*
1271 * v6 mapped
1272 */
1273
1274 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1275
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001276 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 return NULL;
1278
1279 newtcp6sk = (struct tcp6_sock *)newsk;
1280 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1281
1282 newinet = inet_sk(newsk);
1283 newnp = inet6_sk(newsk);
1284 newtp = tcp_sk(newsk);
1285
1286 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1287
1288 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
1289 newinet->daddr);
1290
1291 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
1292 newinet->saddr);
1293
1294 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1295
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001296 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001298#ifdef CONFIG_TCP_MD5SIG
1299 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1300#endif
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 newnp->pktoptions = NULL;
1303 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001304 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001305 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001307 /*
1308 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1309 * here, tcp_create_openreq_child now does this for us, see the comment in
1310 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001314 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 Sync it now.
1316 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001317 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319 return newsk;
1320 }
1321
1322 opt = np->opt;
1323
1324 if (sk_acceptq_is_full(sk))
1325 goto out_overflow;
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (dst == NULL) {
1328 struct in6_addr *final_p = NULL, final;
1329 struct flowi fl;
1330
1331 memset(&fl, 0, sizeof(fl));
1332 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001333 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (opt && opt->srcrt) {
1335 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
1336 ipv6_addr_copy(&final, &fl.fl6_dst);
1337 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1338 final_p = &final;
1339 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001340 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001342 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001344 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 if (ip6_dst_lookup(sk, &dst, &fl))
1347 goto out;
1348
1349 if (final_p)
1350 ipv6_addr_copy(&fl.fl6_dst, final_p);
1351
1352 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
1353 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
1356 newsk = tcp_create_openreq_child(sk, req, skb);
1357 if (newsk == NULL)
1358 goto out;
1359
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001360 /*
1361 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1362 * count here, tcp_create_openreq_child now does this for us, see the
1363 * comment in that function for the gory details. -acme
1364 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Stephen Hemminger59eed272006-08-25 15:55:43 -07001366 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001367 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 newtcp6sk = (struct tcp6_sock *)newsk;
1370 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1371
1372 newtp = tcp_sk(newsk);
1373 newinet = inet_sk(newsk);
1374 newnp = inet6_sk(newsk);
1375
1376 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1377
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001378 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1379 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1380 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1381 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001383 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
1385 First: no IPv4 options.
1386 */
1387 newinet->opt = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001388 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 /* Clone RX bits */
1391 newnp->rxopt.all = np->rxopt.all;
1392
1393 /* Clone pktoptions received with SYN */
1394 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001395 if (treq->pktopts != NULL) {
1396 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1397 kfree_skb(treq->pktopts);
1398 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (newnp->pktoptions)
1400 skb_set_owner_r(newnp->pktoptions, newsk);
1401 }
1402 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001403 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001404 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
1406 /* Clone native IPv6 options from listening socket (if any)
1407
1408 Yes, keeping reference count would be much more clever,
1409 but we make one more one thing there: reattach optmem
1410 to newsk.
1411 */
1412 if (opt) {
1413 newnp->opt = ipv6_dup_options(newsk, opt);
1414 if (opt != np->opt)
1415 sock_kfree_s(sk, opt, opt->tot_len);
1416 }
1417
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001418 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001420 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1421 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
John Heffner5d424d52006-03-20 17:53:41 -08001423 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 tcp_sync_mss(newsk, dst_mtu(dst));
1425 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1426 tcp_initialize_rcv_mss(newsk);
1427
1428 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
1429
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001430#ifdef CONFIG_TCP_MD5SIG
1431 /* Copy over the MD5 key from the original socket */
1432 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1433 /* We're using one, so create a matching key
1434 * on the newsk structure. If we fail to get
1435 * memory, then we end up not copying the key
1436 * across. Shucks.
1437 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001438 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1439 if (newkey != NULL)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001440 tcp_v6_md5_do_add(newsk, &inet6_sk(sk)->daddr,
1441 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001442 }
1443#endif
1444
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001445 __inet6_hash(newsk);
Pavel Emelyanove56d8b82008-04-17 23:17:34 -07001446 __inet_inherit_port(sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
1448 return newsk;
1449
1450out_overflow:
1451 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
1452out:
1453 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
1454 if (opt && opt != np->opt)
1455 sock_kfree_s(sk, opt, opt->tot_len);
1456 dst_release(dst);
1457 return NULL;
1458}
1459
Al Virob51655b2006-11-14 21:40:42 -08001460static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001462 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001463 if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001464 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001465 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001469
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001470 skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001471 &ipv6_hdr(skb)->saddr,
1472 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001473
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001475 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 }
1477 return 0;
1478}
1479
1480/* The socket must have it's spinlock held when we get
1481 * here.
1482 *
1483 * We have a potential double-lock case here, so even when
1484 * doing backlog processing we use the BH locking scheme.
1485 * This is because we cannot sleep with the original spinlock
1486 * held.
1487 */
1488static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1489{
1490 struct ipv6_pinfo *np = inet6_sk(sk);
1491 struct tcp_sock *tp;
1492 struct sk_buff *opt_skb = NULL;
1493
1494 /* Imagine: socket is IPv6. IPv4 packet arrives,
1495 goes to IPv4 receive handler and backlogged.
1496 From backlog it always goes here. Kerboom...
1497 Fortunately, tcp_rcv_established and rcv_established
1498 handle them correctly, but it is not case with
1499 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1500 */
1501
1502 if (skb->protocol == htons(ETH_P_IP))
1503 return tcp_v4_do_rcv(sk, skb);
1504
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001505#ifdef CONFIG_TCP_MD5SIG
1506 if (tcp_v6_inbound_md5_hash (sk, skb))
1507 goto discard;
1508#endif
1509
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001510 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 goto discard;
1512
1513 /*
1514 * socket locking is here for SMP purposes as backlog rcv
1515 * is currently called with bh processing disabled.
1516 */
1517
1518 /* Do Stevens' IPV6_PKTOPTIONS.
1519
1520 Yes, guys, it is the only place in our code, where we
1521 may make it not affecting IPv4.
1522 The rest of code is protocol independent,
1523 and I do not like idea to uglify IPv4.
1524
1525 Actually, all the idea behind IPV6_PKTOPTIONS
1526 looks not very well thought. For now we latch
1527 options, received in the last packet, enqueued
1528 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001529 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 */
1531 if (np->rxopt.all)
1532 opt_skb = skb_clone(skb, GFP_ATOMIC);
1533
1534 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1535 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001536 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 goto reset;
1538 TCP_CHECK_TIMER(sk);
1539 if (opt_skb)
1540 goto ipv6_pktoptions;
1541 return 0;
1542 }
1543
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001544 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 goto csum_err;
1546
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001547 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1549 if (!nsk)
1550 goto discard;
1551
1552 /*
1553 * Queue it on the new socket if the new socket is active,
1554 * otherwise we just shortcircuit this and continue with
1555 * the new socket..
1556 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001557 if(nsk != sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 if (tcp_child_process(sk, nsk, skb))
1559 goto reset;
1560 if (opt_skb)
1561 __kfree_skb(opt_skb);
1562 return 0;
1563 }
1564 }
1565
1566 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001567 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 goto reset;
1569 TCP_CHECK_TIMER(sk);
1570 if (opt_skb)
1571 goto ipv6_pktoptions;
1572 return 0;
1573
1574reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001575 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576discard:
1577 if (opt_skb)
1578 __kfree_skb(opt_skb);
1579 kfree_skb(skb);
1580 return 0;
1581csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001582 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 goto discard;
1584
1585
1586ipv6_pktoptions:
1587 /* Do you ask, what is it?
1588
1589 1. skb was enqueued by tcp.
1590 2. skb is added to tail of read queue, rather than out of order.
1591 3. socket is not in passive state.
1592 4. Finally, it really contains options, which user wants to receive.
1593 */
1594 tp = tcp_sk(sk);
1595 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1596 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001597 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001598 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001599 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001600 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 if (ipv6_opt_accepted(sk, opt_skb)) {
1602 skb_set_owner_r(opt_skb, sk);
1603 opt_skb = xchg(&np->pktoptions, opt_skb);
1604 } else {
1605 __kfree_skb(opt_skb);
1606 opt_skb = xchg(&np->pktoptions, NULL);
1607 }
1608 }
1609
1610 if (opt_skb)
1611 kfree_skb(opt_skb);
1612 return 0;
1613}
1614
Herbert Xue5bbef22007-10-15 12:50:28 -07001615static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616{
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001617 struct tcphdr *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 struct sock *sk;
1619 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001620 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 if (skb->pkt_type != PACKET_HOST)
1623 goto discard_it;
1624
1625 /*
1626 * Count it even if it's bad.
1627 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001628 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
1630 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1631 goto discard_it;
1632
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001633 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
1635 if (th->doff < sizeof(struct tcphdr)/4)
1636 goto bad_packet;
1637 if (!pskb_may_pull(skb, th->doff*4))
1638 goto discard_it;
1639
Herbert Xu60476372007-04-09 11:59:39 -07001640 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 goto bad_packet;
1642
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001643 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1645 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1646 skb->len - th->doff*4);
1647 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1648 TCP_SKB_CB(skb)->when = 0;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001649 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 TCP_SKB_CB(skb)->sacked = 0;
1651
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001652 sk = __inet6_lookup(net, &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001653 &ipv6_hdr(skb)->saddr, th->source,
1654 &ipv6_hdr(skb)->daddr, ntohs(th->dest),
1655 inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657 if (!sk)
1658 goto no_tcp_socket;
1659
1660process:
1661 if (sk->sk_state == TCP_TIME_WAIT)
1662 goto do_time_wait;
1663
1664 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1665 goto discard_and_relse;
1666
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001667 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 goto discard_and_relse;
1669
1670 skb->dev = NULL;
1671
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001672 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 ret = 0;
1674 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001675#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001676 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001677 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
1678 tp->ucopy.dma_chan = get_softnet_dma();
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001679 if (tp->ucopy.dma_chan)
1680 ret = tcp_v6_do_rcv(sk, skb);
1681 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001682#endif
1683 {
1684 if (!tcp_prequeue(sk, skb))
1685 ret = tcp_v6_do_rcv(sk, skb);
1686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 } else
1688 sk_add_backlog(sk, skb);
1689 bh_unlock_sock(sk);
1690
1691 sock_put(sk);
1692 return ret ? -1 : 0;
1693
1694no_tcp_socket:
1695 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1696 goto discard_it;
1697
1698 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1699bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001700 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001702 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 }
1704
1705discard_it:
1706
1707 /*
1708 * Discard frame
1709 */
1710
1711 kfree_skb(skb);
1712 return 0;
1713
1714discard_and_relse:
1715 sock_put(sk);
1716 goto discard_it;
1717
1718do_time_wait:
1719 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001720 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 goto discard_it;
1722 }
1723
1724 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001725 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001726 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 goto discard_it;
1728 }
1729
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001730 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 case TCP_TW_SYN:
1732 {
1733 struct sock *sk2;
1734
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001735 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001736 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001737 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001739 struct inet_timewait_sock *tw = inet_twsk(sk);
1740 inet_twsk_deschedule(tw, &tcp_death_row);
1741 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 sk = sk2;
1743 goto process;
1744 }
1745 /* Fall through to ACK */
1746 }
1747 case TCP_TW_ACK:
1748 tcp_v6_timewait_ack(sk, skb);
1749 break;
1750 case TCP_TW_RST:
1751 goto no_tcp_socket;
1752 case TCP_TW_SUCCESS:;
1753 }
1754 goto discard_it;
1755}
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757static int tcp_v6_remember_stamp(struct sock *sk)
1758{
1759 /* Alas, not yet... */
1760 return 0;
1761}
1762
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001763static struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001764 .queue_xmit = inet6_csk_xmit,
1765 .send_check = tcp_v6_send_check,
1766 .rebuild_header = inet6_sk_rebuild_header,
1767 .conn_request = tcp_v6_conn_request,
1768 .syn_recv_sock = tcp_v6_syn_recv_sock,
1769 .remember_stamp = tcp_v6_remember_stamp,
1770 .net_header_len = sizeof(struct ipv6hdr),
1771 .setsockopt = ipv6_setsockopt,
1772 .getsockopt = ipv6_getsockopt,
1773 .addr2sockaddr = inet6_csk_addr2sockaddr,
1774 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001775 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001776#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001777 .compat_setsockopt = compat_ipv6_setsockopt,
1778 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001779#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780};
1781
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001782#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001783static struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001784 .md5_lookup = tcp_v6_md5_lookup,
1785 .calc_md5_hash = tcp_v6_calc_md5_hash,
1786 .md5_add = tcp_v6_md5_add_func,
1787 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001788};
David S. Millera9286302006-11-14 19:53:22 -08001789#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001790
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791/*
1792 * TCP over IPv4 via INET6 API
1793 */
1794
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001795static struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001796 .queue_xmit = ip_queue_xmit,
1797 .send_check = tcp_v4_send_check,
1798 .rebuild_header = inet_sk_rebuild_header,
1799 .conn_request = tcp_v6_conn_request,
1800 .syn_recv_sock = tcp_v6_syn_recv_sock,
1801 .remember_stamp = tcp_v4_remember_stamp,
1802 .net_header_len = sizeof(struct iphdr),
1803 .setsockopt = ipv6_setsockopt,
1804 .getsockopt = ipv6_getsockopt,
1805 .addr2sockaddr = inet6_csk_addr2sockaddr,
1806 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001807 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001808#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001809 .compat_setsockopt = compat_ipv6_setsockopt,
1810 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001811#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812};
1813
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001814#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001815static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001816 .md5_lookup = tcp_v4_md5_lookup,
1817 .calc_md5_hash = tcp_v4_calc_md5_hash,
1818 .md5_add = tcp_v6_md5_add_func,
1819 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001820};
David S. Millera9286302006-11-14 19:53:22 -08001821#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001822
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823/* NOTE: A lot of things set to zero explicitly by call to
1824 * sk_alloc() so need not be done here.
1825 */
1826static int tcp_v6_init_sock(struct sock *sk)
1827{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001828 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 struct tcp_sock *tp = tcp_sk(sk);
1830
1831 skb_queue_head_init(&tp->out_of_order_queue);
1832 tcp_init_xmit_timers(sk);
1833 tcp_prequeue_init(tp);
1834
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001835 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 tp->mdev = TCP_TIMEOUT_INIT;
1837
1838 /* So many TCP implementations out there (incorrectly) count the
1839 * initial SYN frame in their delayed-ACK and congestion control
1840 * algorithms that we must have the following bandaid to talk
1841 * efficiently to them. -DaveM
1842 */
1843 tp->snd_cwnd = 2;
1844
1845 /* See draft-stevens-tcpca-spec-01 for discussion of the
1846 * initialization of these values.
1847 */
1848 tp->snd_ssthresh = 0x7fffffff;
1849 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001850 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852 tp->reordering = sysctl_tcp_reordering;
1853
1854 sk->sk_state = TCP_CLOSE;
1855
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001856 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001857 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001858 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 sk->sk_write_space = sk_stream_write_space;
1860 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1861
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001862#ifdef CONFIG_TCP_MD5SIG
1863 tp->af_specific = &tcp_sock_ipv6_specific;
1864#endif
1865
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1867 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1868
1869 atomic_inc(&tcp_sockets_allocated);
1870
1871 return 0;
1872}
1873
Brian Haley7d06b2e2008-06-14 17:04:49 -07001874static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001876#ifdef CONFIG_TCP_MD5SIG
1877 /* Clean up the MD5 key list */
1878 if (tcp_sk(sk)->md5sig_info)
1879 tcp_v6_clear_md5_list(sk);
1880#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001882 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883}
1884
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09001885#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001887static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001888 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001891 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1892 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
1894 if (ttd < 0)
1895 ttd = 0;
1896
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 seq_printf(seq,
1898 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1899 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1900 i,
1901 src->s6_addr32[0], src->s6_addr32[1],
1902 src->s6_addr32[2], src->s6_addr32[3],
1903 ntohs(inet_sk(sk)->sport),
1904 dest->s6_addr32[0], dest->s6_addr32[1],
1905 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001906 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 TCP_SYN_RECV,
1908 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001909 1, /* timers active (only the expire timer) */
1910 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 req->retrans,
1912 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001913 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 0, /* open_requests have no inode */
1915 0, req);
1916}
1917
1918static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1919{
1920 struct in6_addr *dest, *src;
1921 __u16 destp, srcp;
1922 int timer_active;
1923 unsigned long timer_expires;
1924 struct inet_sock *inet = inet_sk(sp);
1925 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001926 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 struct ipv6_pinfo *np = inet6_sk(sp);
1928
1929 dest = &np->daddr;
1930 src = &np->rcv_saddr;
1931 destp = ntohs(inet->dport);
1932 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001933
1934 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001936 timer_expires = icsk->icsk_timeout;
1937 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001939 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 } else if (timer_pending(&sp->sk_timer)) {
1941 timer_active = 2;
1942 timer_expires = sp->sk_timer.expires;
1943 } else {
1944 timer_active = 0;
1945 timer_expires = jiffies;
1946 }
1947
1948 seq_printf(seq,
1949 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Stephen Hemminger7be87352008-06-27 20:00:19 -07001950 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 i,
1952 src->s6_addr32[0], src->s6_addr32[1],
1953 src->s6_addr32[2], src->s6_addr32[3], srcp,
1954 dest->s6_addr32[0], dest->s6_addr32[1],
1955 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001956 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07001957 tp->write_seq-tp->snd_una,
1958 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 timer_active,
1960 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001961 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001963 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 sock_i_ino(sp),
1965 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07001966 jiffies_to_clock_t(icsk->icsk_rto),
1967 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001968 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
1970 );
1971}
1972
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001973static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001974 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975{
1976 struct in6_addr *dest, *src;
1977 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001978 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 int ttd = tw->tw_ttd - jiffies;
1980
1981 if (ttd < 0)
1982 ttd = 0;
1983
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001984 dest = &tw6->tw_v6_daddr;
1985 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 destp = ntohs(tw->tw_dport);
1987 srcp = ntohs(tw->tw_sport);
1988
1989 seq_printf(seq,
1990 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1991 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1992 i,
1993 src->s6_addr32[0], src->s6_addr32[1],
1994 src->s6_addr32[2], src->s6_addr32[3], srcp,
1995 dest->s6_addr32[0], dest->s6_addr32[1],
1996 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1997 tw->tw_substate, 0, 0,
1998 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1999 atomic_read(&tw->tw_refcnt), tw);
2000}
2001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002static int tcp6_seq_show(struct seq_file *seq, void *v)
2003{
2004 struct tcp_iter_state *st;
2005
2006 if (v == SEQ_START_TOKEN) {
2007 seq_puts(seq,
2008 " sl "
2009 "local_address "
2010 "remote_address "
2011 "st tx_queue rx_queue tr tm->when retrnsmt"
2012 " uid timeout inode\n");
2013 goto out;
2014 }
2015 st = seq->private;
2016
2017 switch (st->state) {
2018 case TCP_SEQ_STATE_LISTENING:
2019 case TCP_SEQ_STATE_ESTABLISHED:
2020 get_tcp6_sock(seq, v, st->num);
2021 break;
2022 case TCP_SEQ_STATE_OPENREQ:
2023 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
2024 break;
2025 case TCP_SEQ_STATE_TIME_WAIT:
2026 get_timewait6_sock(seq, v, st->num);
2027 break;
2028 }
2029out:
2030 return 0;
2031}
2032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 .name = "tcp6",
2035 .family = AF_INET6,
Denis V. Lunev5f4472c2008-04-13 22:13:53 -07002036 .seq_fops = {
2037 .owner = THIS_MODULE,
2038 },
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07002039 .seq_ops = {
2040 .show = tcp6_seq_show,
2041 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042};
2043
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002044int tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002046 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047}
2048
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002049void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002051 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052}
2053#endif
2054
2055struct proto tcpv6_prot = {
2056 .name = "TCPv6",
2057 .owner = THIS_MODULE,
2058 .close = tcp_close,
2059 .connect = tcp_v6_connect,
2060 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002061 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 .ioctl = tcp_ioctl,
2063 .init = tcp_v6_init_sock,
2064 .destroy = tcp_v6_destroy_sock,
2065 .shutdown = tcp_shutdown,
2066 .setsockopt = tcp_setsockopt,
2067 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 .recvmsg = tcp_recvmsg,
2069 .backlog_rcv = tcp_v6_do_rcv,
2070 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08002071 .unhash = inet_unhash,
2072 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 .enter_memory_pressure = tcp_enter_memory_pressure,
2074 .sockets_allocated = &tcp_sockets_allocated,
2075 .memory_allocated = &tcp_memory_allocated,
2076 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002077 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 .sysctl_mem = sysctl_tcp_mem,
2079 .sysctl_wmem = sysctl_tcp_wmem,
2080 .sysctl_rmem = sysctl_tcp_rmem,
2081 .max_header = MAX_TCP_HEADER,
2082 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002083 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002084 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002085 .h.hashinfo = &tcp_hashinfo,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002086#ifdef CONFIG_COMPAT
2087 .compat_setsockopt = compat_tcp_setsockopt,
2088 .compat_getsockopt = compat_tcp_getsockopt,
2089#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090};
2091
2092static struct inet6_protocol tcpv6_protocol = {
2093 .handler = tcp_v6_rcv,
2094 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002095 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002096 .gso_segment = tcp_tso_segment,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2098};
2099
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100static struct inet_protosw tcpv6_protosw = {
2101 .type = SOCK_STREAM,
2102 .protocol = IPPROTO_TCP,
2103 .prot = &tcpv6_prot,
2104 .ops = &inet6_stream_ops,
2105 .capability = -1,
2106 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002107 .flags = INET_PROTOSW_PERMANENT |
2108 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109};
2110
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002111static int tcpv6_net_init(struct net *net)
2112{
Denis V. Lunev56772422008-04-03 14:28:30 -07002113 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2114 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002115}
2116
2117static void tcpv6_net_exit(struct net *net)
2118{
Denis V. Lunev56772422008-04-03 14:28:30 -07002119 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002120}
2121
2122static struct pernet_operations tcpv6_net_ops = {
2123 .init = tcpv6_net_init,
2124 .exit = tcpv6_net_exit,
2125};
2126
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002127int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002129 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002130
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002131 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2132 if (ret)
2133 goto out;
2134
2135 /* register inet6 protocol */
2136 ret = inet6_register_protosw(&tcpv6_protosw);
2137 if (ret)
2138 goto out_tcpv6_protocol;
2139
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002140 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002141 if (ret)
2142 goto out_tcpv6_protosw;
2143out:
2144 return ret;
2145
2146out_tcpv6_protocol:
2147 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2148out_tcpv6_protosw:
2149 inet6_unregister_protosw(&tcpv6_protosw);
2150 goto out;
2151}
2152
Daniel Lezcano09f77092007-12-13 05:34:58 -08002153void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002154{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002155 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002156 inet6_unregister_protosw(&tcpv6_protosw);
2157 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158}