blob: ecdbb9f46541ca1c2ef65a955248c62f12914b11 [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 *
8 * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $
9 *
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +090010 * Based on:
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 * linux/net/ipv4/tcp.c
12 * linux/net/ipv4/tcp_input.c
13 * linux/net/ipv4/tcp_output.c
14 *
15 * Fixes:
16 * Hideaki YOSHIFUJI : sin6_scope_id support
17 * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
18 * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
19 * a single port at the same time.
20 * YOSHIFUJI Hideaki @USAGI: convert /proc/net/tcp6 to seq_file.
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version
25 * 2 of the License, or (at your option) any later version.
26 */
27
28#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/errno.h>
30#include <linux/types.h>
31#include <linux/socket.h>
32#include <linux/sockios.h>
33#include <linux/net.h>
34#include <linux/jiffies.h>
35#include <linux/in.h>
36#include <linux/in6.h>
37#include <linux/netdevice.h>
38#include <linux/init.h>
39#include <linux/jhash.h>
40#include <linux/ipsec.h>
41#include <linux/times.h>
42
43#include <linux/ipv6.h>
44#include <linux/icmpv6.h>
45#include <linux/random.h>
46
47#include <net/tcp.h>
48#include <net/ndisc.h>
Arnaldo Carvalho de Melo5324a042005-08-12 09:26:18 -030049#include <net/inet6_hashtables.h>
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -080050#include <net/inet6_connection_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <net/ipv6.h>
52#include <net/transp_v6.h>
53#include <net/addrconf.h>
54#include <net/ip6_route.h>
55#include <net/ip6_checksum.h>
56#include <net/inet_ecn.h>
57#include <net/protocol.h>
58#include <net/xfrm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <net/snmp.h>
60#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080061#include <net/timewait_sock.h>
Jeff Garzik18134be2007-10-26 22:53:14 -070062#include <net/netdma.h>
Denis V. Lunev3d58b5f2008-04-03 14:22:32 -070063#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include <asm/uaccess.h>
66
67#include <linux/proc_fs.h>
68#include <linux/seq_file.h>
69
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080070#include <linux/crypto.h>
71#include <linux/scatterlist.h>
72
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080073static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -070074static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +090075static void tcp_v6_send_check(struct sock *sk, int len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 struct sk_buff *skb);
77
78static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080080static struct inet_connection_sock_af_ops ipv6_mapped;
81static struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080082#ifdef CONFIG_TCP_MD5SIG
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080083static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
84static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090085#else
86static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
87 struct in6_addr *addr)
88{
89 return NULL;
90}
David S. Millera9286302006-11-14 19:53:22 -080091#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static void tcp_v6_hash(struct sock *sk)
94{
95 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080096 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 tcp_prot.hash(sk);
98 return;
99 }
100 local_bh_disable();
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -0800101 __inet6_hash(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 local_bh_enable();
103 }
104}
105
Al Viro868c86b2006-11-14 21:35:48 -0800106static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900107 struct in6_addr *saddr,
108 struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800109 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
111 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
112}
113
Gerrit Renkera94f7232006-11-10 14:06:49 -0800114static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700116 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
117 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700118 tcp_hdr(skb)->dest,
119 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120}
121
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900122static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 int addr_len)
124{
125 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900126 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800127 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 struct ipv6_pinfo *np = inet6_sk(sk);
129 struct tcp_sock *tp = tcp_sk(sk);
130 struct in6_addr *saddr = NULL, *final_p = NULL, final;
131 struct flowi fl;
132 struct dst_entry *dst;
133 int addr_type;
134 int err;
135
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900136 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 return -EINVAL;
138
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900139 if (usin->sin6_family != AF_INET6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 return(-EAFNOSUPPORT);
141
142 memset(&fl, 0, sizeof(fl));
143
144 if (np->sndflow) {
145 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
146 IP6_ECN_flow_init(fl.fl6_flowlabel);
147 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
148 struct ip6_flowlabel *flowlabel;
149 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
150 if (flowlabel == NULL)
151 return -EINVAL;
152 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
153 fl6_sock_release(flowlabel);
154 }
155 }
156
157 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900158 * connect() to INADDR_ANY means loopback (BSD'ism).
159 */
160
161 if(ipv6_addr_any(&usin->sin6_addr))
162 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 addr_type = ipv6_addr_type(&usin->sin6_addr);
165
166 if(addr_type & IPV6_ADDR_MULTICAST)
167 return -ENETUNREACH;
168
169 if (addr_type&IPV6_ADDR_LINKLOCAL) {
170 if (addr_len >= sizeof(struct sockaddr_in6) &&
171 usin->sin6_scope_id) {
172 /* If interface is set while binding, indices
173 * must coincide.
174 */
175 if (sk->sk_bound_dev_if &&
176 sk->sk_bound_dev_if != usin->sin6_scope_id)
177 return -EINVAL;
178
179 sk->sk_bound_dev_if = usin->sin6_scope_id;
180 }
181
182 /* Connect to link-local address requires an interface */
183 if (!sk->sk_bound_dev_if)
184 return -EINVAL;
185 }
186
187 if (tp->rx_opt.ts_recent_stamp &&
188 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
189 tp->rx_opt.ts_recent = 0;
190 tp->rx_opt.ts_recent_stamp = 0;
191 tp->write_seq = 0;
192 }
193
194 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
195 np->flow_label = fl.fl6_flowlabel;
196
197 /*
198 * TCP over IPv4
199 */
200
201 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800202 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 struct sockaddr_in sin;
204
205 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
206
207 if (__ipv6_only_sock(sk))
208 return -ENETUNREACH;
209
210 sin.sin_family = AF_INET;
211 sin.sin_port = usin->sin6_port;
212 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
213
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800214 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800216#ifdef CONFIG_TCP_MD5SIG
217 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
218#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
221
222 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800223 icsk->icsk_ext_hdr_len = exthdrlen;
224 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800226#ifdef CONFIG_TCP_MD5SIG
227 tp->af_specific = &tcp_sock_ipv6_specific;
228#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 goto failure;
230 } else {
231 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
232 inet->saddr);
233 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
234 inet->rcv_saddr);
235 }
236
237 return err;
238 }
239
240 if (!ipv6_addr_any(&np->rcv_saddr))
241 saddr = &np->rcv_saddr;
242
243 fl.proto = IPPROTO_TCP;
244 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
245 ipv6_addr_copy(&fl.fl6_src,
246 (saddr ? saddr : &np->saddr));
247 fl.oif = sk->sk_bound_dev_if;
248 fl.fl_ip_dport = usin->sin6_port;
249 fl.fl_ip_sport = inet->sport;
250
251 if (np->opt && np->opt->srcrt) {
252 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
253 ipv6_addr_copy(&final, &fl.fl6_dst);
254 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
255 final_p = &final;
256 }
257
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700258 security_sk_classify_flow(sk, &fl);
259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 err = ip6_dst_lookup(sk, &dst, &fl);
261 if (err)
262 goto failure;
263 if (final_p)
264 ipv6_addr_copy(&fl.fl6_dst, final_p);
265
Herbert Xubb728452007-12-12 18:48:58 -0800266 if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
David S. Miller14e50e52007-05-24 18:17:54 -0700267 if (err == -EREMOTE)
268 err = ip6_dst_blackhole(sk, &dst, &fl);
269 if (err < 0)
270 goto failure;
271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 if (saddr == NULL) {
274 saddr = &fl.fl6_src;
275 ipv6_addr_copy(&np->rcv_saddr, saddr);
276 }
277
278 /* set the source address */
279 ipv6_addr_copy(&np->saddr, saddr);
280 inet->rcv_saddr = LOOPBACK4_IPV6;
281
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700282 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700283 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800285 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800287 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
288 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
291
292 inet->dport = usin->sin6_port;
293
294 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800295 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if (err)
297 goto late_failure;
298
299 if (!tp->write_seq)
300 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
301 np->daddr.s6_addr32,
302 inet->sport,
303 inet->dport);
304
305 err = tcp_connect(sk);
306 if (err)
307 goto late_failure;
308
309 return 0;
310
311late_failure:
312 tcp_set_state(sk, TCP_CLOSE);
313 __sk_dst_reset(sk);
314failure:
315 inet->dport = 0;
316 sk->sk_route_caps = 0;
317 return err;
318}
319
320static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Al Viro04ce6902006-11-08 00:21:01 -0800321 int type, int code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
323 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300324 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 struct ipv6_pinfo *np;
326 struct sock *sk;
327 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900328 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 __u32 seq;
330
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900331 sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800332 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334 if (sk == NULL) {
335 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
336 return;
337 }
338
339 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700340 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 return;
342 }
343
344 bh_lock_sock(sk);
345 if (sock_owned_by_user(sk))
346 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
347
348 if (sk->sk_state == TCP_CLOSE)
349 goto out;
350
351 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900352 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 if (sk->sk_state != TCP_LISTEN &&
354 !between(seq, tp->snd_una, tp->snd_nxt)) {
355 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
356 goto out;
357 }
358
359 np = inet6_sk(sk);
360
361 if (type == ICMPV6_PKT_TOOBIG) {
362 struct dst_entry *dst = NULL;
363
364 if (sock_owned_by_user(sk))
365 goto out;
366 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
367 goto out;
368
369 /* icmp should have updated the destination cache entry */
370 dst = __sk_dst_check(sk, np->dst_cookie);
371
372 if (dst == NULL) {
373 struct inet_sock *inet = inet_sk(sk);
374 struct flowi fl;
375
376 /* BUGGG_FUTURE: Again, it is not clear how
377 to handle rthdr case. Ignore this complexity
378 for now.
379 */
380 memset(&fl, 0, sizeof(fl));
381 fl.proto = IPPROTO_TCP;
382 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
383 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
384 fl.oif = sk->sk_bound_dev_if;
385 fl.fl_ip_dport = inet->dport;
386 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700387 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
390 sk->sk_err_soft = -err;
391 goto out;
392 }
393
394 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
395 sk->sk_err_soft = -err;
396 goto out;
397 }
398
399 } else
400 dst_hold(dst);
401
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800402 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 tcp_sync_mss(sk, dst_mtu(dst));
404 tcp_simple_retransmit(sk);
405 } /* else let the usual retransmit timer handle it */
406 dst_release(dst);
407 goto out;
408 }
409
410 icmpv6_err_convert(type, code, &err);
411
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700412 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700414 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 case TCP_LISTEN:
416 if (sock_owned_by_user(sk))
417 goto out;
418
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800419 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
420 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 if (!req)
422 goto out;
423
424 /* ICMPs are not backlogged, hence we cannot get
425 * an established socket here.
426 */
427 BUG_TRAP(req->sk == NULL);
428
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700429 if (seq != tcp_rsk(req)->snt_isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
431 goto out;
432 }
433
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700434 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 goto out;
436
437 case TCP_SYN_SENT:
438 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900439 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 sk->sk_err = err;
442 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
443
444 tcp_done(sk);
445 } else
446 sk->sk_err_soft = err;
447 goto out;
448 }
449
450 if (!sock_owned_by_user(sk) && np->recverr) {
451 sk->sk_err = err;
452 sk->sk_error_report(sk);
453 } else
454 sk->sk_err_soft = err;
455
456out:
457 bh_unlock_sock(sk);
458 sock_put(sk);
459}
460
461
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800462static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800464 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 struct ipv6_pinfo *np = inet6_sk(sk);
466 struct sk_buff * skb;
467 struct ipv6_txoptions *opt = NULL;
468 struct in6_addr * final_p = NULL, final;
469 struct flowi fl;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800470 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 int err = -1;
472
473 memset(&fl, 0, sizeof(fl));
474 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700475 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
476 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700478 fl.oif = treq->iif;
479 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700481 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800483 opt = np->opt;
484 if (opt && opt->srcrt) {
485 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
486 ipv6_addr_copy(&final, &fl.fl6_dst);
487 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
488 final_p = &final;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 }
490
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800491 err = ip6_dst_lookup(sk, &dst, &fl);
492 if (err)
493 goto done;
494 if (final_p)
495 ipv6_addr_copy(&fl.fl6_dst, final_p);
496 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
497 goto done;
498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 skb = tcp_make_synack(sk, dst, req);
500 if (skb) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700501 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 th->check = tcp_v6_check(th, skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700504 &treq->loc_addr, &treq->rmt_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 csum_partial((char *)th, skb->len, skb->csum));
506
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700507 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 err = ip6_xmit(sk, skb, &fl, opt, 0);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200509 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
511
512done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900513 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800515 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 return err;
517}
518
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800519static inline void syn_flood_warning(struct sk_buff *skb)
520{
521#ifdef CONFIG_SYN_COOKIES
522 if (sysctl_tcp_syncookies)
523 printk(KERN_INFO
524 "TCPv6: Possible SYN flooding on port %d. "
525 "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
526 else
527#endif
528 printk(KERN_INFO
529 "TCPv6: Possible SYN flooding on port %d. "
530 "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
531}
532
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700533static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800535 if (inet6_rsk(req)->pktopts)
536 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800539#ifdef CONFIG_TCP_MD5SIG
540static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
541 struct in6_addr *addr)
542{
543 struct tcp_sock *tp = tcp_sk(sk);
544 int i;
545
546 BUG_ON(tp == NULL);
547
548 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
549 return NULL;
550
551 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900552 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
David S. Millerf8ab18d2007-09-28 15:18:35 -0700553 return &tp->md5sig_info->keys6[i].base;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800554 }
555 return NULL;
556}
557
558static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
559 struct sock *addr_sk)
560{
561 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
562}
563
564static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
565 struct request_sock *req)
566{
567 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
568}
569
570static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
571 char *newkey, u8 newkeylen)
572{
573 /* Add key to the list */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700574 struct tcp_md5sig_key *key;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800575 struct tcp_sock *tp = tcp_sk(sk);
576 struct tcp6_md5sig_key *keys;
577
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700578 key = tcp_v6_md5_do_lookup(sk, peer);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800579 if (key) {
580 /* modify existing entry - just update that one */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700581 kfree(key->key);
582 key->key = newkey;
583 key->keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800584 } else {
585 /* reallocate new list if current one is full. */
586 if (!tp->md5sig_info) {
587 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
588 if (!tp->md5sig_info) {
589 kfree(newkey);
590 return -ENOMEM;
591 }
David S. Miller3d7dbea2007-06-12 14:36:42 -0700592 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800593 }
YOSHIFUJI Hideakiaacbe8c2007-11-20 17:30:56 -0800594 if (tcp_alloc_md5sig_pool() == NULL) {
595 kfree(newkey);
596 return -ENOMEM;
597 }
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800598 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
599 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
600 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
601
602 if (!keys) {
603 tcp_free_md5sig_pool();
604 kfree(newkey);
605 return -ENOMEM;
606 }
607
608 if (tp->md5sig_info->entries6)
609 memmove(keys, tp->md5sig_info->keys6,
610 (sizeof (tp->md5sig_info->keys6[0]) *
611 tp->md5sig_info->entries6));
612
613 kfree(tp->md5sig_info->keys6);
614 tp->md5sig_info->keys6 = keys;
615 tp->md5sig_info->alloced6++;
616 }
617
618 ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
619 peer);
David S. Millerf8ab18d2007-09-28 15:18:35 -0700620 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
621 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800622
623 tp->md5sig_info->entries6++;
624 }
625 return 0;
626}
627
628static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
629 u8 *newkey, __u8 newkeylen)
630{
631 return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr,
632 newkey, newkeylen);
633}
634
635static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
636{
637 struct tcp_sock *tp = tcp_sk(sk);
638 int i;
639
640 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900641 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800642 /* Free the key */
David S. Millerf8ab18d2007-09-28 15:18:35 -0700643 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800644 tp->md5sig_info->entries6--;
645
646 if (tp->md5sig_info->entries6 == 0) {
647 kfree(tp->md5sig_info->keys6);
648 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700649 tp->md5sig_info->alloced6 = 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800650 } else {
651 /* shrink the database */
652 if (tp->md5sig_info->entries6 != i)
653 memmove(&tp->md5sig_info->keys6[i],
654 &tp->md5sig_info->keys6[i+1],
655 (tp->md5sig_info->entries6 - i)
656 * sizeof (tp->md5sig_info->keys6[0]));
657 }
YOSHIFUJI Hideaki77adefd2007-11-20 17:31:23 -0800658 tcp_free_md5sig_pool();
659 return 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800660 }
661 }
662 return -ENOENT;
663}
664
665static void tcp_v6_clear_md5_list (struct sock *sk)
666{
667 struct tcp_sock *tp = tcp_sk(sk);
668 int i;
669
670 if (tp->md5sig_info->entries6) {
671 for (i = 0; i < tp->md5sig_info->entries6; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700672 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800673 tp->md5sig_info->entries6 = 0;
674 tcp_free_md5sig_pool();
675 }
676
677 kfree(tp->md5sig_info->keys6);
678 tp->md5sig_info->keys6 = NULL;
679 tp->md5sig_info->alloced6 = 0;
680
681 if (tp->md5sig_info->entries4) {
682 for (i = 0; i < tp->md5sig_info->entries4; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700683 kfree(tp->md5sig_info->keys4[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800684 tp->md5sig_info->entries4 = 0;
685 tcp_free_md5sig_pool();
686 }
687
688 kfree(tp->md5sig_info->keys4);
689 tp->md5sig_info->keys4 = NULL;
690 tp->md5sig_info->alloced4 = 0;
691}
692
693static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
694 int optlen)
695{
696 struct tcp_md5sig cmd;
697 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
698 u8 *newkey;
699
700 if (optlen < sizeof(cmd))
701 return -EINVAL;
702
703 if (copy_from_user(&cmd, optval, sizeof(cmd)))
704 return -EFAULT;
705
706 if (sin6->sin6_family != AF_INET6)
707 return -EINVAL;
708
709 if (!cmd.tcpm_keylen) {
710 if (!tcp_sk(sk)->md5sig_info)
711 return -ENOENT;
Brian Haleye773e4f2007-08-24 23:16:08 -0700712 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800713 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
714 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
715 }
716
717 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
718 return -EINVAL;
719
720 if (!tcp_sk(sk)->md5sig_info) {
721 struct tcp_sock *tp = tcp_sk(sk);
722 struct tcp_md5sig_info *p;
723
724 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
725 if (!p)
726 return -ENOMEM;
727
728 tp->md5sig_info = p;
David S. Miller3d7dbea2007-06-12 14:36:42 -0700729 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800730 }
731
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200732 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800733 if (!newkey)
734 return -ENOMEM;
Brian Haleye773e4f2007-08-24 23:16:08 -0700735 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800736 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
737 newkey, cmd.tcpm_keylen);
738 }
739 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
740}
741
742static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
743 struct in6_addr *saddr,
744 struct in6_addr *daddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900745 struct tcphdr *th, unsigned int tcplen)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800746{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800747 struct tcp_md5sig_pool *hp;
748 struct tcp6_pseudohdr *bp;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800749 int err;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800750
751 hp = tcp_get_md5sig_pool();
752 if (!hp) {
Harvey Harrison0dc47872008-03-05 20:47:47 -0800753 printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800754 goto clear_hash_noput;
755 }
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900756
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800757 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800758
759 /* 1. TCP pseudo-header (RFC2460) */
760 ipv6_addr_copy(&bp->saddr, saddr);
761 ipv6_addr_copy(&bp->daddr, daddr);
762 bp->len = htonl(tcplen);
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900763 bp->protocol = htonl(IPPROTO_TCP);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800764
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900765 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
766 th, tcplen, hp);
David S. Millerc7da57a2007-10-26 00:41:21 -0700767
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900768 if (err)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800769 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800770
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900771 /* Free up the crypto pool */
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800772 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800773out:
774 return 0;
775clear_hash:
776 tcp_put_md5sig_pool();
777clear_hash_noput:
778 memset(md5_hash, 0, 16);
779 goto out;
780}
781
782static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
783 struct sock *sk,
784 struct dst_entry *dst,
785 struct request_sock *req,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900786 struct tcphdr *th, unsigned int tcplen)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800787{
788 struct in6_addr *saddr, *daddr;
789
790 if (sk) {
791 saddr = &inet6_sk(sk)->saddr;
792 daddr = &inet6_sk(sk)->daddr;
793 } else {
794 saddr = &inet6_rsk(req)->loc_addr;
795 daddr = &inet6_rsk(req)->rmt_addr;
796 }
797 return tcp_v6_do_calc_md5_hash(md5_hash, key,
798 saddr, daddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900799 th, tcplen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800800}
801
802static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
803{
804 __u8 *hash_location = NULL;
805 struct tcp_md5sig_key *hash_expected;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700806 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700807 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800808 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800809 u8 newhash[16];
810
811 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900812 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800813
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800814 /* do we have a hash as expected? */
815 if (!hash_expected) {
816 if (!hash_location)
817 return 0;
818 if (net_ratelimit()) {
819 printk(KERN_INFO "MD5 Hash NOT expected but found "
820 "(" NIP6_FMT ", %u)->"
821 "(" NIP6_FMT ", %u)\n",
822 NIP6(ip6h->saddr), ntohs(th->source),
823 NIP6(ip6h->daddr), ntohs(th->dest));
824 }
825 return 1;
826 }
827
828 if (!hash_location) {
829 if (net_ratelimit()) {
830 printk(KERN_INFO "MD5 Hash expected but NOT found "
831 "(" NIP6_FMT ", %u)->"
832 "(" NIP6_FMT ", %u)\n",
833 NIP6(ip6h->saddr), ntohs(th->source),
834 NIP6(ip6h->daddr), ntohs(th->dest));
835 }
836 return 1;
837 }
838
839 /* check the signature */
840 genhash = tcp_v6_do_calc_md5_hash(newhash,
841 hash_expected,
842 &ip6h->saddr, &ip6h->daddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900843 th, skb->len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800844 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
845 if (net_ratelimit()) {
846 printk(KERN_INFO "MD5 Hash %s for "
847 "(" NIP6_FMT ", %u)->"
848 "(" NIP6_FMT ", %u)\n",
849 genhash ? "failed" : "mismatch",
850 NIP6(ip6h->saddr), ntohs(th->source),
851 NIP6(ip6h->daddr), ntohs(th->dest));
852 }
853 return 1;
854 }
855 return 0;
856}
857#endif
858
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800859struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700861 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700863 .send_ack = tcp_v6_reqsk_send_ack,
864 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 .send_reset = tcp_v6_send_reset
866};
867
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800868#ifdef CONFIG_TCP_MD5SIG
Andrew Mortonb6332e62006-11-30 19:16:28 -0800869static struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800870 .md5_lookup = tcp_v6_reqsk_md5_lookup,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800871};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800872#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800873
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800874static struct timewait_sock_ops tcp6_timewait_sock_ops = {
875 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
876 .twsk_unique = tcp_twsk_unique,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800877 .twsk_destructor= tcp_twsk_destructor,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800878};
879
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800880static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700883 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Patrick McHardy84fa7932006-08-29 16:44:56 -0700885 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700887 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800888 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 } else {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900890 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
891 csum_partial((char *)th, th->doff<<2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 skb->csum));
893 }
894}
895
Herbert Xua430a432006-07-08 13:34:56 -0700896static int tcp_v6_gso_send_check(struct sk_buff *skb)
897{
898 struct ipv6hdr *ipv6h;
899 struct tcphdr *th;
900
901 if (!pskb_may_pull(skb, sizeof(*th)))
902 return -EINVAL;
903
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700904 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700905 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700906
907 th->check = 0;
908 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
909 IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700910 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800911 skb->csum_offset = offsetof(struct tcphdr, check);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700912 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xua430a432006-07-08 13:34:56 -0700913 return 0;
914}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800916static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700918 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 struct sk_buff *buff;
920 struct flowi fl;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +0900921 struct net *net = dev_net(skb->dst->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -0800922 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -0800923 unsigned int tot_len = sizeof(*th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800924#ifdef CONFIG_TCP_MD5SIG
925 struct tcp_md5sig_key *key;
926#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 if (th->rst)
929 return;
930
931 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900932 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800934#ifdef CONFIG_TCP_MD5SIG
935 if (sk)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700936 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800937 else
938 key = NULL;
939
940 if (key)
941 tot_len += TCPOLEN_MD5SIG_ALIGNED;
942#endif
943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 /*
945 * We need to grab some memory, and put together an RST,
946 * and then put it into the queue to be sent.
947 */
948
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800949 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 GFP_ATOMIC);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900951 if (buff == NULL)
952 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800954 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800956 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 /* Swap the send and the receive. */
959 memset(t1, 0, sizeof(*t1));
960 t1->dest = th->source;
961 t1->source = th->dest;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800962 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 t1->rst = 1;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 if(th->ack) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900966 t1->seq = th->ack_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 } else {
968 t1->ack = 1;
969 t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
970 + skb->len - (th->doff<<2));
971 }
972
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800973#ifdef CONFIG_TCP_MD5SIG
974 if (key) {
Al Viro8e5200f2006-11-20 18:06:37 -0800975 __be32 *opt = (__be32*)(t1 + 1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800976 opt[0] = htonl((TCPOPT_NOP << 24) |
977 (TCPOPT_NOP << 16) |
978 (TCPOPT_MD5SIG << 8) |
979 TCPOLEN_MD5SIG);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700980 tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key,
981 &ipv6_hdr(skb)->daddr,
982 &ipv6_hdr(skb)->saddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +0900983 t1, tot_len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800984 }
985#endif
986
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
988
989 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700990 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
991 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
994 sizeof(*t1), IPPROTO_TCP,
995 buff->csum);
996
997 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300998 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 fl.fl_ip_dport = t1->dest;
1000 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001001 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
Daniel Lezcanoc20121a2008-03-05 10:48:35 -08001003 /* Pass a socket to ip6_dst_lookup either it is for RST
1004 * Underlying function will use this to retrieve the network
1005 * namespace
1006 */
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001007 if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001009 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001010 ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001011 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
1012 TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 }
1016
1017 kfree_skb(buff);
1018}
1019
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001020static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
1021 struct tcp_md5sig_key *key)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001023 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 struct sk_buff *buff;
1025 struct flowi fl;
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001026 struct net *net = dev_net(skb->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001027 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -08001028 unsigned int tot_len = sizeof(struct tcphdr);
Al Viroe69a4ad2006-11-14 20:56:00 -08001029 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
1031 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -07001032 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001033#ifdef CONFIG_TCP_MD5SIG
1034 if (key)
1035 tot_len += TCPOLEN_MD5SIG_ALIGNED;
1036#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
1039 GFP_ATOMIC);
1040 if (buff == NULL)
1041 return;
1042
1043 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
1044
1045 t1 = (struct tcphdr *) skb_push(buff,tot_len);
1046
1047 /* Swap the send and the receive. */
1048 memset(t1, 0, sizeof(*t1));
1049 t1->dest = th->source;
1050 t1->source = th->dest;
1051 t1->doff = tot_len/4;
1052 t1->seq = htonl(seq);
1053 t1->ack_seq = htonl(ack);
1054 t1->ack = 1;
1055 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001056
Al Viroe69a4ad2006-11-14 20:56:00 -08001057 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001060 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1061 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
1062 *topt++ = htonl(tcp_time_stamp);
1063 *topt = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 }
1065
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001066#ifdef CONFIG_TCP_MD5SIG
1067 if (key) {
1068 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1069 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001070 tcp_v6_do_calc_md5_hash((__u8 *)topt, key,
1071 &ipv6_hdr(skb)->daddr,
1072 &ipv6_hdr(skb)->saddr,
YOSHIFUJI Hideaki076fb722008-04-17 12:48:12 +09001073 t1, tot_len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001074 }
1075#endif
1076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 buff->csum = csum_partial((char *)t1, tot_len, 0);
1078
1079 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001080 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1081 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
1084 tot_len, IPPROTO_TCP,
1085 buff->csum);
1086
1087 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001088 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 fl.fl_ip_dport = t1->dest;
1090 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001091 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001093 if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001094 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001095 ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001096 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
1100
1101 kfree_skb(buff);
1102}
1103
1104static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1105{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001106 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001107 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001109 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001110 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001111 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001113 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114}
1115
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001116static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001118 tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
1119 tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
1121
1122
1123static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1124{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001125 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001126 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 struct sock *nsk;
1128
1129 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001130 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001131 &ipv6_hdr(skb)->saddr,
1132 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (req)
1134 return tcp_check_req(sk, skb, req, prev);
1135
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001136 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001137 &ipv6_hdr(skb)->saddr, th->source,
1138 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
1140 if (nsk) {
1141 if (nsk->sk_state != TCP_TIME_WAIT) {
1142 bh_lock_sock(nsk);
1143 return nsk;
1144 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001145 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 return NULL;
1147 }
1148
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001149#ifdef CONFIG_SYN_COOKIES
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if (!th->rst && !th->syn && th->ack)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001151 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152#endif
1153 return sk;
1154}
1155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156/* FIXME: this is substantially similar to the ipv4 code.
1157 * Can some kind of merge be done? -- erics
1158 */
1159static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1160{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001161 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 struct ipv6_pinfo *np = inet6_sk(sk);
1163 struct tcp_options_received tmp_opt;
1164 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001165 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 __u32 isn = TCP_SKB_CB(skb)->when;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001167#ifdef CONFIG_SYN_COOKIES
1168 int want_cookie = 0;
1169#else
1170#define want_cookie 0
1171#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
1173 if (skb->protocol == htons(ETH_P_IP))
1174 return tcp_v4_conn_request(sk, skb);
1175
1176 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001177 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001179 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 if (net_ratelimit())
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001181 syn_flood_warning(skb);
1182#ifdef CONFIG_SYN_COOKIES
1183 if (sysctl_tcp_syncookies)
1184 want_cookie = 1;
1185 else
1186#endif
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001187 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001190 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 goto drop;
1192
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001193 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (req == NULL)
1195 goto drop;
1196
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001197#ifdef CONFIG_TCP_MD5SIG
1198 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1199#endif
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 tcp_clear_options(&tmp_opt);
1202 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1203 tmp_opt.user_mss = tp->rx_opt.user_mss;
1204
1205 tcp_parse_options(skb, &tmp_opt, 0);
1206
Florian Westphal4dfc2812008-04-10 03:12:40 -07001207 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001208 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001209
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1211 tcp_openreq_init(req, &tmp_opt, skb);
1212
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001213 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001214 ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
1215 ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001216 treq->pktopts = NULL;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001217 if (!want_cookie)
1218 TCP_ECN_create_request(req, tcp_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001220 if (want_cookie) {
1221 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
Florian Westphal4dfc2812008-04-10 03:12:40 -07001222 req->cookie_ts = tmp_opt.tstamp_ok;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001223 } else if (!isn) {
1224 if (ipv6_opt_accepted(sk, skb) ||
1225 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1226 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1227 atomic_inc(&skb->users);
1228 treq->pktopts = skb;
1229 }
1230 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001232 /* So that link locals have meaning */
1233 if (!sk->sk_bound_dev_if &&
1234 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1235 treq->iif = inet6_iif(skb);
1236
Gerrit Renkera94f7232006-11-10 14:06:49 -08001237 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001240 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001242 security_inet_conn_request(sk, skb, req);
1243
Denis V. Lunevfd80eb92008-02-29 11:43:03 -08001244 if (tcp_v6_send_synack(sk, req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 goto drop;
1246
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001247 if (!want_cookie) {
1248 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1249 return 0;
1250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252drop:
1253 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001254 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 return 0; /* don't send reset */
1257}
1258
1259static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001260 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 struct dst_entry *dst)
1262{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001263 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1265 struct tcp6_sock *newtcp6sk;
1266 struct inet_sock *newinet;
1267 struct tcp_sock *newtp;
1268 struct sock *newsk;
1269 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001270#ifdef CONFIG_TCP_MD5SIG
1271 struct tcp_md5sig_key *key;
1272#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
1274 if (skb->protocol == htons(ETH_P_IP)) {
1275 /*
1276 * v6 mapped
1277 */
1278
1279 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1280
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001281 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 return NULL;
1283
1284 newtcp6sk = (struct tcp6_sock *)newsk;
1285 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1286
1287 newinet = inet_sk(newsk);
1288 newnp = inet6_sk(newsk);
1289 newtp = tcp_sk(newsk);
1290
1291 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1292
1293 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
1294 newinet->daddr);
1295
1296 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
1297 newinet->saddr);
1298
1299 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1300
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001301 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001303#ifdef CONFIG_TCP_MD5SIG
1304 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1305#endif
1306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 newnp->pktoptions = NULL;
1308 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001309 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001310 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001312 /*
1313 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1314 * here, tcp_create_openreq_child now does this for us, see the comment in
1315 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001319 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 Sync it now.
1321 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001322 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
1324 return newsk;
1325 }
1326
1327 opt = np->opt;
1328
1329 if (sk_acceptq_is_full(sk))
1330 goto out_overflow;
1331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 if (dst == NULL) {
1333 struct in6_addr *final_p = NULL, final;
1334 struct flowi fl;
1335
1336 memset(&fl, 0, sizeof(fl));
1337 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001338 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 if (opt && opt->srcrt) {
1340 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
1341 ipv6_addr_copy(&final, &fl.fl6_dst);
1342 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1343 final_p = &final;
1344 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001345 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001347 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001349 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
1351 if (ip6_dst_lookup(sk, &dst, &fl))
1352 goto out;
1353
1354 if (final_p)
1355 ipv6_addr_copy(&fl.fl6_dst, final_p);
1356
1357 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
1358 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 newsk = tcp_create_openreq_child(sk, req, skb);
1362 if (newsk == NULL)
1363 goto out;
1364
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001365 /*
1366 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1367 * count here, tcp_create_openreq_child now does this for us, see the
1368 * comment in that function for the gory details. -acme
1369 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Stephen Hemminger59eed272006-08-25 15:55:43 -07001371 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001372 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 newtcp6sk = (struct tcp6_sock *)newsk;
1375 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1376
1377 newtp = tcp_sk(newsk);
1378 newinet = inet_sk(newsk);
1379 newnp = inet6_sk(newsk);
1380
1381 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1382
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001383 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1384 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1385 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1386 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001388 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 First: no IPv4 options.
1391 */
1392 newinet->opt = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001393 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 /* Clone RX bits */
1396 newnp->rxopt.all = np->rxopt.all;
1397
1398 /* Clone pktoptions received with SYN */
1399 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001400 if (treq->pktopts != NULL) {
1401 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1402 kfree_skb(treq->pktopts);
1403 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if (newnp->pktoptions)
1405 skb_set_owner_r(newnp->pktoptions, newsk);
1406 }
1407 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001408 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001409 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 /* Clone native IPv6 options from listening socket (if any)
1412
1413 Yes, keeping reference count would be much more clever,
1414 but we make one more one thing there: reattach optmem
1415 to newsk.
1416 */
1417 if (opt) {
1418 newnp->opt = ipv6_dup_options(newsk, opt);
1419 if (opt != np->opt)
1420 sock_kfree_s(sk, opt, opt->tot_len);
1421 }
1422
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001423 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001425 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1426 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
John Heffner5d424d52006-03-20 17:53:41 -08001428 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 tcp_sync_mss(newsk, dst_mtu(dst));
1430 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1431 tcp_initialize_rcv_mss(newsk);
1432
1433 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
1434
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001435#ifdef CONFIG_TCP_MD5SIG
1436 /* Copy over the MD5 key from the original socket */
1437 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1438 /* We're using one, so create a matching key
1439 * on the newsk structure. If we fail to get
1440 * memory, then we end up not copying the key
1441 * across. Shucks.
1442 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001443 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1444 if (newkey != NULL)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001445 tcp_v6_md5_do_add(newsk, &inet6_sk(sk)->daddr,
1446 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001447 }
1448#endif
1449
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001450 __inet6_hash(newsk);
Pavel Emelyanove56d8b82008-04-17 23:17:34 -07001451 __inet_inherit_port(sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
1453 return newsk;
1454
1455out_overflow:
1456 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
1457out:
1458 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
1459 if (opt && opt != np->opt)
1460 sock_kfree_s(sk, opt, opt->tot_len);
1461 dst_release(dst);
1462 return NULL;
1463}
1464
Al Virob51655b2006-11-14 21:40:42 -08001465static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001467 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001468 if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001469 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001470 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001474
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001475 skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001476 &ipv6_hdr(skb)->saddr,
1477 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001478
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001480 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 }
1482 return 0;
1483}
1484
1485/* The socket must have it's spinlock held when we get
1486 * here.
1487 *
1488 * We have a potential double-lock case here, so even when
1489 * doing backlog processing we use the BH locking scheme.
1490 * This is because we cannot sleep with the original spinlock
1491 * held.
1492 */
1493static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1494{
1495 struct ipv6_pinfo *np = inet6_sk(sk);
1496 struct tcp_sock *tp;
1497 struct sk_buff *opt_skb = NULL;
1498
1499 /* Imagine: socket is IPv6. IPv4 packet arrives,
1500 goes to IPv4 receive handler and backlogged.
1501 From backlog it always goes here. Kerboom...
1502 Fortunately, tcp_rcv_established and rcv_established
1503 handle them correctly, but it is not case with
1504 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1505 */
1506
1507 if (skb->protocol == htons(ETH_P_IP))
1508 return tcp_v4_do_rcv(sk, skb);
1509
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001510#ifdef CONFIG_TCP_MD5SIG
1511 if (tcp_v6_inbound_md5_hash (sk, skb))
1512 goto discard;
1513#endif
1514
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001515 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 goto discard;
1517
1518 /*
1519 * socket locking is here for SMP purposes as backlog rcv
1520 * is currently called with bh processing disabled.
1521 */
1522
1523 /* Do Stevens' IPV6_PKTOPTIONS.
1524
1525 Yes, guys, it is the only place in our code, where we
1526 may make it not affecting IPv4.
1527 The rest of code is protocol independent,
1528 and I do not like idea to uglify IPv4.
1529
1530 Actually, all the idea behind IPV6_PKTOPTIONS
1531 looks not very well thought. For now we latch
1532 options, received in the last packet, enqueued
1533 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001534 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 */
1536 if (np->rxopt.all)
1537 opt_skb = skb_clone(skb, GFP_ATOMIC);
1538
1539 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1540 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001541 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 goto reset;
1543 TCP_CHECK_TIMER(sk);
1544 if (opt_skb)
1545 goto ipv6_pktoptions;
1546 return 0;
1547 }
1548
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001549 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 goto csum_err;
1551
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001552 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1554 if (!nsk)
1555 goto discard;
1556
1557 /*
1558 * Queue it on the new socket if the new socket is active,
1559 * otherwise we just shortcircuit this and continue with
1560 * the new socket..
1561 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001562 if(nsk != sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 if (tcp_child_process(sk, nsk, skb))
1564 goto reset;
1565 if (opt_skb)
1566 __kfree_skb(opt_skb);
1567 return 0;
1568 }
1569 }
1570
1571 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001572 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 goto reset;
1574 TCP_CHECK_TIMER(sk);
1575 if (opt_skb)
1576 goto ipv6_pktoptions;
1577 return 0;
1578
1579reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001580 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581discard:
1582 if (opt_skb)
1583 __kfree_skb(opt_skb);
1584 kfree_skb(skb);
1585 return 0;
1586csum_err:
1587 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1588 goto discard;
1589
1590
1591ipv6_pktoptions:
1592 /* Do you ask, what is it?
1593
1594 1. skb was enqueued by tcp.
1595 2. skb is added to tail of read queue, rather than out of order.
1596 3. socket is not in passive state.
1597 4. Finally, it really contains options, which user wants to receive.
1598 */
1599 tp = tcp_sk(sk);
1600 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1601 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001602 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001603 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001604 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001605 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (ipv6_opt_accepted(sk, opt_skb)) {
1607 skb_set_owner_r(opt_skb, sk);
1608 opt_skb = xchg(&np->pktoptions, opt_skb);
1609 } else {
1610 __kfree_skb(opt_skb);
1611 opt_skb = xchg(&np->pktoptions, NULL);
1612 }
1613 }
1614
1615 if (opt_skb)
1616 kfree_skb(opt_skb);
1617 return 0;
1618}
1619
Herbert Xue5bbef22007-10-15 12:50:28 -07001620static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621{
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001622 struct tcphdr *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 struct sock *sk;
1624 int ret;
1625
1626 if (skb->pkt_type != PACKET_HOST)
1627 goto discard_it;
1628
1629 /*
1630 * Count it even if it's bad.
1631 */
1632 TCP_INC_STATS_BH(TCP_MIB_INSEGS);
1633
1634 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1635 goto discard_it;
1636
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001637 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
1639 if (th->doff < sizeof(struct tcphdr)/4)
1640 goto bad_packet;
1641 if (!pskb_may_pull(skb, th->doff*4))
1642 goto discard_it;
1643
Herbert Xu60476372007-04-09 11:59:39 -07001644 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 goto bad_packet;
1646
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001647 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1649 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1650 skb->len - th->doff*4);
1651 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1652 TCP_SKB_CB(skb)->when = 0;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001653 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 TCP_SKB_CB(skb)->sacked = 0;
1655
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001656 sk = __inet6_lookup(dev_net(skb->dev), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001657 &ipv6_hdr(skb)->saddr, th->source,
1658 &ipv6_hdr(skb)->daddr, ntohs(th->dest),
1659 inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 if (!sk)
1662 goto no_tcp_socket;
1663
1664process:
1665 if (sk->sk_state == TCP_TIME_WAIT)
1666 goto do_time_wait;
1667
1668 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1669 goto discard_and_relse;
1670
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001671 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 goto discard_and_relse;
1673
1674 skb->dev = NULL;
1675
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001676 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 ret = 0;
1678 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001679#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001680 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001681 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
1682 tp->ucopy.dma_chan = get_softnet_dma();
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001683 if (tp->ucopy.dma_chan)
1684 ret = tcp_v6_do_rcv(sk, skb);
1685 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001686#endif
1687 {
1688 if (!tcp_prequeue(sk, skb))
1689 ret = tcp_v6_do_rcv(sk, skb);
1690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 } else
1692 sk_add_backlog(sk, skb);
1693 bh_unlock_sock(sk);
1694
1695 sock_put(sk);
1696 return ret ? -1 : 0;
1697
1698no_tcp_socket:
1699 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1700 goto discard_it;
1701
1702 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1703bad_packet:
1704 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1705 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001706 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 }
1708
1709discard_it:
1710
1711 /*
1712 * Discard frame
1713 */
1714
1715 kfree_skb(skb);
1716 return 0;
1717
1718discard_and_relse:
1719 sock_put(sk);
1720 goto discard_it;
1721
1722do_time_wait:
1723 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001724 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 goto discard_it;
1726 }
1727
1728 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1729 TCP_INC_STATS_BH(TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001730 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 goto discard_it;
1732 }
1733
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001734 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 case TCP_TW_SYN:
1736 {
1737 struct sock *sk2;
1738
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001739 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001740 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001741 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001743 struct inet_timewait_sock *tw = inet_twsk(sk);
1744 inet_twsk_deschedule(tw, &tcp_death_row);
1745 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 sk = sk2;
1747 goto process;
1748 }
1749 /* Fall through to ACK */
1750 }
1751 case TCP_TW_ACK:
1752 tcp_v6_timewait_ack(sk, skb);
1753 break;
1754 case TCP_TW_RST:
1755 goto no_tcp_socket;
1756 case TCP_TW_SUCCESS:;
1757 }
1758 goto discard_it;
1759}
1760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761static int tcp_v6_remember_stamp(struct sock *sk)
1762{
1763 /* Alas, not yet... */
1764 return 0;
1765}
1766
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001767static struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001768 .queue_xmit = inet6_csk_xmit,
1769 .send_check = tcp_v6_send_check,
1770 .rebuild_header = inet6_sk_rebuild_header,
1771 .conn_request = tcp_v6_conn_request,
1772 .syn_recv_sock = tcp_v6_syn_recv_sock,
1773 .remember_stamp = tcp_v6_remember_stamp,
1774 .net_header_len = sizeof(struct ipv6hdr),
1775 .setsockopt = ipv6_setsockopt,
1776 .getsockopt = ipv6_getsockopt,
1777 .addr2sockaddr = inet6_csk_addr2sockaddr,
1778 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001779 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001780#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001781 .compat_setsockopt = compat_ipv6_setsockopt,
1782 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001783#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784};
1785
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001786#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001787static struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001788 .md5_lookup = tcp_v6_md5_lookup,
1789 .calc_md5_hash = tcp_v6_calc_md5_hash,
1790 .md5_add = tcp_v6_md5_add_func,
1791 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001792};
David S. Millera9286302006-11-14 19:53:22 -08001793#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001794
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795/*
1796 * TCP over IPv4 via INET6 API
1797 */
1798
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001799static struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001800 .queue_xmit = ip_queue_xmit,
1801 .send_check = tcp_v4_send_check,
1802 .rebuild_header = inet_sk_rebuild_header,
1803 .conn_request = tcp_v6_conn_request,
1804 .syn_recv_sock = tcp_v6_syn_recv_sock,
1805 .remember_stamp = tcp_v4_remember_stamp,
1806 .net_header_len = sizeof(struct iphdr),
1807 .setsockopt = ipv6_setsockopt,
1808 .getsockopt = ipv6_getsockopt,
1809 .addr2sockaddr = inet6_csk_addr2sockaddr,
1810 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001811 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001812#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001813 .compat_setsockopt = compat_ipv6_setsockopt,
1814 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001815#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816};
1817
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001818#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001819static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001820 .md5_lookup = tcp_v4_md5_lookup,
1821 .calc_md5_hash = tcp_v4_calc_md5_hash,
1822 .md5_add = tcp_v6_md5_add_func,
1823 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001824};
David S. Millera9286302006-11-14 19:53:22 -08001825#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001826
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827/* NOTE: A lot of things set to zero explicitly by call to
1828 * sk_alloc() so need not be done here.
1829 */
1830static int tcp_v6_init_sock(struct sock *sk)
1831{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001832 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 struct tcp_sock *tp = tcp_sk(sk);
1834
1835 skb_queue_head_init(&tp->out_of_order_queue);
1836 tcp_init_xmit_timers(sk);
1837 tcp_prequeue_init(tp);
1838
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001839 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 tp->mdev = TCP_TIMEOUT_INIT;
1841
1842 /* So many TCP implementations out there (incorrectly) count the
1843 * initial SYN frame in their delayed-ACK and congestion control
1844 * algorithms that we must have the following bandaid to talk
1845 * efficiently to them. -DaveM
1846 */
1847 tp->snd_cwnd = 2;
1848
1849 /* See draft-stevens-tcpca-spec-01 for discussion of the
1850 * initialization of these values.
1851 */
1852 tp->snd_ssthresh = 0x7fffffff;
1853 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001854 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
1856 tp->reordering = sysctl_tcp_reordering;
1857
1858 sk->sk_state = TCP_CLOSE;
1859
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001860 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001861 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001862 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 sk->sk_write_space = sk_stream_write_space;
1864 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1865
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001866#ifdef CONFIG_TCP_MD5SIG
1867 tp->af_specific = &tcp_sock_ipv6_specific;
1868#endif
1869
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1871 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1872
1873 atomic_inc(&tcp_sockets_allocated);
1874
1875 return 0;
1876}
1877
1878static int tcp_v6_destroy_sock(struct sock *sk)
1879{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001880#ifdef CONFIG_TCP_MD5SIG
1881 /* Clean up the MD5 key list */
1882 if (tcp_sk(sk)->md5sig_info)
1883 tcp_v6_clear_md5_list(sk);
1884#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 tcp_v4_destroy_sock(sk);
1886 return inet6_destroy_sock(sk);
1887}
1888
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09001889#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001891static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001892 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001895 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1896 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
1898 if (ttd < 0)
1899 ttd = 0;
1900
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 seq_printf(seq,
1902 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1903 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1904 i,
1905 src->s6_addr32[0], src->s6_addr32[1],
1906 src->s6_addr32[2], src->s6_addr32[3],
1907 ntohs(inet_sk(sk)->sport),
1908 dest->s6_addr32[0], dest->s6_addr32[1],
1909 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001910 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 TCP_SYN_RECV,
1912 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001913 1, /* timers active (only the expire timer) */
1914 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 req->retrans,
1916 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001917 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 0, /* open_requests have no inode */
1919 0, req);
1920}
1921
1922static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1923{
1924 struct in6_addr *dest, *src;
1925 __u16 destp, srcp;
1926 int timer_active;
1927 unsigned long timer_expires;
1928 struct inet_sock *inet = inet_sk(sp);
1929 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001930 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 struct ipv6_pinfo *np = inet6_sk(sp);
1932
1933 dest = &np->daddr;
1934 src = &np->rcv_saddr;
1935 destp = ntohs(inet->dport);
1936 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001937
1938 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001940 timer_expires = icsk->icsk_timeout;
1941 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001943 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 } else if (timer_pending(&sp->sk_timer)) {
1945 timer_active = 2;
1946 timer_expires = sp->sk_timer.expires;
1947 } else {
1948 timer_active = 0;
1949 timer_expires = jiffies;
1950 }
1951
1952 seq_printf(seq,
1953 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1954 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
1955 i,
1956 src->s6_addr32[0], src->s6_addr32[1],
1957 src->s6_addr32[2], src->s6_addr32[3], srcp,
1958 dest->s6_addr32[0], dest->s6_addr32[1],
1959 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001960 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07001961 tp->write_seq-tp->snd_una,
1962 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 timer_active,
1964 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001965 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001967 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 sock_i_ino(sp),
1969 atomic_read(&sp->sk_refcnt), sp,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001970 icsk->icsk_rto,
1971 icsk->icsk_ack.ato,
1972 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
1974 );
1975}
1976
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001977static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001978 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 struct in6_addr *dest, *src;
1981 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001982 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 int ttd = tw->tw_ttd - jiffies;
1984
1985 if (ttd < 0)
1986 ttd = 0;
1987
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001988 dest = &tw6->tw_v6_daddr;
1989 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 destp = ntohs(tw->tw_dport);
1991 srcp = ntohs(tw->tw_sport);
1992
1993 seq_printf(seq,
1994 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1995 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1996 i,
1997 src->s6_addr32[0], src->s6_addr32[1],
1998 src->s6_addr32[2], src->s6_addr32[3], srcp,
1999 dest->s6_addr32[0], dest->s6_addr32[1],
2000 dest->s6_addr32[2], dest->s6_addr32[3], destp,
2001 tw->tw_substate, 0, 0,
2002 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
2003 atomic_read(&tw->tw_refcnt), tw);
2004}
2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006static int tcp6_seq_show(struct seq_file *seq, void *v)
2007{
2008 struct tcp_iter_state *st;
2009
2010 if (v == SEQ_START_TOKEN) {
2011 seq_puts(seq,
2012 " sl "
2013 "local_address "
2014 "remote_address "
2015 "st tx_queue rx_queue tr tm->when retrnsmt"
2016 " uid timeout inode\n");
2017 goto out;
2018 }
2019 st = seq->private;
2020
2021 switch (st->state) {
2022 case TCP_SEQ_STATE_LISTENING:
2023 case TCP_SEQ_STATE_ESTABLISHED:
2024 get_tcp6_sock(seq, v, st->num);
2025 break;
2026 case TCP_SEQ_STATE_OPENREQ:
2027 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
2028 break;
2029 case TCP_SEQ_STATE_TIME_WAIT:
2030 get_timewait6_sock(seq, v, st->num);
2031 break;
2032 }
2033out:
2034 return 0;
2035}
2036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 .name = "tcp6",
2039 .family = AF_INET6,
Denis V. Lunev5f4472c2008-04-13 22:13:53 -07002040 .seq_fops = {
2041 .owner = THIS_MODULE,
2042 },
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07002043 .seq_ops = {
2044 .show = tcp6_seq_show,
2045 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046};
2047
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002048int tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002050 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051}
2052
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002053void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002055 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056}
2057#endif
2058
2059struct proto tcpv6_prot = {
2060 .name = "TCPv6",
2061 .owner = THIS_MODULE,
2062 .close = tcp_close,
2063 .connect = tcp_v6_connect,
2064 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002065 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 .ioctl = tcp_ioctl,
2067 .init = tcp_v6_init_sock,
2068 .destroy = tcp_v6_destroy_sock,
2069 .shutdown = tcp_shutdown,
2070 .setsockopt = tcp_setsockopt,
2071 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 .recvmsg = tcp_recvmsg,
2073 .backlog_rcv = tcp_v6_do_rcv,
2074 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08002075 .unhash = inet_unhash,
2076 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 .enter_memory_pressure = tcp_enter_memory_pressure,
2078 .sockets_allocated = &tcp_sockets_allocated,
2079 .memory_allocated = &tcp_memory_allocated,
2080 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002081 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 .sysctl_mem = sysctl_tcp_mem,
2083 .sysctl_wmem = sysctl_tcp_wmem,
2084 .sysctl_rmem = sysctl_tcp_rmem,
2085 .max_header = MAX_TCP_HEADER,
2086 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002087 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002088 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002089 .h.hashinfo = &tcp_hashinfo,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002090#ifdef CONFIG_COMPAT
2091 .compat_setsockopt = compat_tcp_setsockopt,
2092 .compat_getsockopt = compat_tcp_getsockopt,
2093#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094};
2095
2096static struct inet6_protocol tcpv6_protocol = {
2097 .handler = tcp_v6_rcv,
2098 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002099 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002100 .gso_segment = tcp_tso_segment,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2102};
2103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104static struct inet_protosw tcpv6_protosw = {
2105 .type = SOCK_STREAM,
2106 .protocol = IPPROTO_TCP,
2107 .prot = &tcpv6_prot,
2108 .ops = &inet6_stream_ops,
2109 .capability = -1,
2110 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002111 .flags = INET_PROTOSW_PERMANENT |
2112 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113};
2114
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002115static int tcpv6_net_init(struct net *net)
2116{
Denis V. Lunev56772422008-04-03 14:28:30 -07002117 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2118 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002119}
2120
2121static void tcpv6_net_exit(struct net *net)
2122{
Denis V. Lunev56772422008-04-03 14:28:30 -07002123 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002124}
2125
2126static struct pernet_operations tcpv6_net_ops = {
2127 .init = tcpv6_net_init,
2128 .exit = tcpv6_net_exit,
2129};
2130
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002131int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002133 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002134
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002135 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2136 if (ret)
2137 goto out;
2138
2139 /* register inet6 protocol */
2140 ret = inet6_register_protosw(&tcpv6_protosw);
2141 if (ret)
2142 goto out_tcpv6_protocol;
2143
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002144 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002145 if (ret)
2146 goto out_tcpv6_protosw;
2147out:
2148 return ret;
2149
2150out_tcpv6_protocol:
2151 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2152out_tcpv6_protosw:
2153 inet6_unregister_protosw(&tcpv6_protosw);
2154 goto out;
2155}
2156
Daniel Lezcano09f77092007-12-13 05:34:58 -08002157void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002158{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002159 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002160 inet6_unregister_protosw(&tcpv6_protosw);
2161 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162}