blob: 9a88395a7629e69c1c2b3e2cd46ad985b0cf68a0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * TCP over IPv6
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 *
8 * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $
9 *
10 * Based on:
11 * 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>
59#include <net/addrconf.h>
60#include <net/snmp.h>
61#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080062#include <net/timewait_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64#include <asm/uaccess.h>
65
66#include <linux/proc_fs.h>
67#include <linux/seq_file.h>
68
David Woodhouseae0f7d52006-01-11 15:53:04 -080069/* Socket used for sending RSTs and ACKs */
70static struct socket *tcp6_socket;
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072static void tcp_v6_send_reset(struct sk_buff *skb);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -070073static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080074static void tcp_v6_send_check(struct sock *sk, int len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 struct sk_buff *skb);
76
77static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080079static struct inet_connection_sock_af_ops ipv6_mapped;
80static struct inet_connection_sock_af_ops ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
83{
Arnaldo Carvalho de Melo971af182005-12-13 23:14:47 -080084 return inet_csk_get_port(&tcp_hashinfo, sk, snum,
85 inet6_csk_bind_conflict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static void tcp_v6_hash(struct sock *sk)
89{
90 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080091 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 tcp_prot.hash(sk);
93 return;
94 }
95 local_bh_disable();
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -080096 __inet6_hash(&tcp_hashinfo, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 local_bh_enable();
98 }
99}
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
102 struct in6_addr *saddr,
103 struct in6_addr *daddr,
104 unsigned long base)
105{
106 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
107}
108
Gerrit Renkera94f7232006-11-10 14:06:49 -0800109static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
Gerrit Renkera94f7232006-11-10 14:06:49 -0800111 return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
112 skb->nh.ipv6h->saddr.s6_addr32,
113 skb->h.th->dest,
114 skb->h.th->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115}
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
118 int addr_len)
119{
120 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800121 struct inet_sock *inet = inet_sk(sk);
122 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 struct ipv6_pinfo *np = inet6_sk(sk);
124 struct tcp_sock *tp = tcp_sk(sk);
125 struct in6_addr *saddr = NULL, *final_p = NULL, final;
126 struct flowi fl;
127 struct dst_entry *dst;
128 int addr_type;
129 int err;
130
131 if (addr_len < SIN6_LEN_RFC2133)
132 return -EINVAL;
133
134 if (usin->sin6_family != AF_INET6)
135 return(-EAFNOSUPPORT);
136
137 memset(&fl, 0, sizeof(fl));
138
139 if (np->sndflow) {
140 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
141 IP6_ECN_flow_init(fl.fl6_flowlabel);
142 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
143 struct ip6_flowlabel *flowlabel;
144 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
145 if (flowlabel == NULL)
146 return -EINVAL;
147 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
148 fl6_sock_release(flowlabel);
149 }
150 }
151
152 /*
153 * connect() to INADDR_ANY means loopback (BSD'ism).
154 */
155
156 if(ipv6_addr_any(&usin->sin6_addr))
157 usin->sin6_addr.s6_addr[15] = 0x1;
158
159 addr_type = ipv6_addr_type(&usin->sin6_addr);
160
161 if(addr_type & IPV6_ADDR_MULTICAST)
162 return -ENETUNREACH;
163
164 if (addr_type&IPV6_ADDR_LINKLOCAL) {
165 if (addr_len >= sizeof(struct sockaddr_in6) &&
166 usin->sin6_scope_id) {
167 /* If interface is set while binding, indices
168 * must coincide.
169 */
170 if (sk->sk_bound_dev_if &&
171 sk->sk_bound_dev_if != usin->sin6_scope_id)
172 return -EINVAL;
173
174 sk->sk_bound_dev_if = usin->sin6_scope_id;
175 }
176
177 /* Connect to link-local address requires an interface */
178 if (!sk->sk_bound_dev_if)
179 return -EINVAL;
180 }
181
182 if (tp->rx_opt.ts_recent_stamp &&
183 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
184 tp->rx_opt.ts_recent = 0;
185 tp->rx_opt.ts_recent_stamp = 0;
186 tp->write_seq = 0;
187 }
188
189 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
190 np->flow_label = fl.fl6_flowlabel;
191
192 /*
193 * TCP over IPv4
194 */
195
196 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800197 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 struct sockaddr_in sin;
199
200 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
201
202 if (__ipv6_only_sock(sk))
203 return -ENETUNREACH;
204
205 sin.sin_family = AF_INET;
206 sin.sin_port = usin->sin6_port;
207 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
208
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800209 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 sk->sk_backlog_rcv = tcp_v4_do_rcv;
211
212 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
213
214 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800215 icsk->icsk_ext_hdr_len = exthdrlen;
216 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 sk->sk_backlog_rcv = tcp_v6_do_rcv;
218 goto failure;
219 } else {
220 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
221 inet->saddr);
222 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
223 inet->rcv_saddr);
224 }
225
226 return err;
227 }
228
229 if (!ipv6_addr_any(&np->rcv_saddr))
230 saddr = &np->rcv_saddr;
231
232 fl.proto = IPPROTO_TCP;
233 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
234 ipv6_addr_copy(&fl.fl6_src,
235 (saddr ? saddr : &np->saddr));
236 fl.oif = sk->sk_bound_dev_if;
237 fl.fl_ip_dport = usin->sin6_port;
238 fl.fl_ip_sport = inet->sport;
239
240 if (np->opt && np->opt->srcrt) {
241 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
242 ipv6_addr_copy(&final, &fl.fl6_dst);
243 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
244 final_p = &final;
245 }
246
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700247 security_sk_classify_flow(sk, &fl);
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 err = ip6_dst_lookup(sk, &dst, &fl);
250 if (err)
251 goto failure;
252 if (final_p)
253 ipv6_addr_copy(&fl.fl6_dst, final_p);
254
Patrick McHardye1044112005-09-08 15:11:55 -0700255 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 if (saddr == NULL) {
259 saddr = &fl.fl6_src;
260 ipv6_addr_copy(&np->rcv_saddr, saddr);
261 }
262
263 /* set the source address */
264 ipv6_addr_copy(&np->saddr, saddr);
265 inet->rcv_saddr = LOOPBACK4_IPV6;
266
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700267 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700268 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800270 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800272 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
273 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
276
277 inet->dport = usin->sin6_port;
278
279 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800280 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 if (err)
282 goto late_failure;
283
284 if (!tp->write_seq)
285 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
286 np->daddr.s6_addr32,
287 inet->sport,
288 inet->dport);
289
290 err = tcp_connect(sk);
291 if (err)
292 goto late_failure;
293
294 return 0;
295
296late_failure:
297 tcp_set_state(sk, TCP_CLOSE);
298 __sk_dst_reset(sk);
299failure:
300 inet->dport = 0;
301 sk->sk_route_caps = 0;
302 return err;
303}
304
305static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Al Viro04ce6902006-11-08 00:21:01 -0800306 int type, int code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307{
308 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300309 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 struct ipv6_pinfo *np;
311 struct sock *sk;
312 int err;
313 struct tcp_sock *tp;
314 __u32 seq;
315
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300316 sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
317 th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 if (sk == NULL) {
320 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
321 return;
322 }
323
324 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700325 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 return;
327 }
328
329 bh_lock_sock(sk);
330 if (sock_owned_by_user(sk))
331 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
332
333 if (sk->sk_state == TCP_CLOSE)
334 goto out;
335
336 tp = tcp_sk(sk);
337 seq = ntohl(th->seq);
338 if (sk->sk_state != TCP_LISTEN &&
339 !between(seq, tp->snd_una, tp->snd_nxt)) {
340 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
341 goto out;
342 }
343
344 np = inet6_sk(sk);
345
346 if (type == ICMPV6_PKT_TOOBIG) {
347 struct dst_entry *dst = NULL;
348
349 if (sock_owned_by_user(sk))
350 goto out;
351 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
352 goto out;
353
354 /* icmp should have updated the destination cache entry */
355 dst = __sk_dst_check(sk, np->dst_cookie);
356
357 if (dst == NULL) {
358 struct inet_sock *inet = inet_sk(sk);
359 struct flowi fl;
360
361 /* BUGGG_FUTURE: Again, it is not clear how
362 to handle rthdr case. Ignore this complexity
363 for now.
364 */
365 memset(&fl, 0, sizeof(fl));
366 fl.proto = IPPROTO_TCP;
367 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
368 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
369 fl.oif = sk->sk_bound_dev_if;
370 fl.fl_ip_dport = inet->dport;
371 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700372 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
375 sk->sk_err_soft = -err;
376 goto out;
377 }
378
379 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
380 sk->sk_err_soft = -err;
381 goto out;
382 }
383
384 } else
385 dst_hold(dst);
386
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800387 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 tcp_sync_mss(sk, dst_mtu(dst));
389 tcp_simple_retransmit(sk);
390 } /* else let the usual retransmit timer handle it */
391 dst_release(dst);
392 goto out;
393 }
394
395 icmpv6_err_convert(type, code, &err);
396
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700397 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700399 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 case TCP_LISTEN:
401 if (sock_owned_by_user(sk))
402 goto out;
403
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800404 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
405 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 if (!req)
407 goto out;
408
409 /* ICMPs are not backlogged, hence we cannot get
410 * an established socket here.
411 */
412 BUG_TRAP(req->sk == NULL);
413
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700414 if (seq != tcp_rsk(req)->snt_isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
416 goto out;
417 }
418
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700419 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 goto out;
421
422 case TCP_SYN_SENT:
423 case TCP_SYN_RECV: /* Cannot happen.
424 It can, it SYNs are crossed. --ANK */
425 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 sk->sk_err = err;
427 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
428
429 tcp_done(sk);
430 } else
431 sk->sk_err_soft = err;
432 goto out;
433 }
434
435 if (!sock_owned_by_user(sk) && np->recverr) {
436 sk->sk_err = err;
437 sk->sk_error_report(sk);
438 } else
439 sk->sk_err_soft = err;
440
441out:
442 bh_unlock_sock(sk);
443 sock_put(sk);
444}
445
446
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700447static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 struct dst_entry *dst)
449{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800450 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct ipv6_pinfo *np = inet6_sk(sk);
452 struct sk_buff * skb;
453 struct ipv6_txoptions *opt = NULL;
454 struct in6_addr * final_p = NULL, final;
455 struct flowi fl;
456 int err = -1;
457
458 memset(&fl, 0, sizeof(fl));
459 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700460 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
461 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700463 fl.oif = treq->iif;
464 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700466 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468 if (dst == NULL) {
469 opt = np->opt;
470 if (opt == NULL &&
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900471 np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700472 treq->pktopts) {
473 struct sk_buff *pktopts = treq->pktopts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 struct inet6_skb_parm *rxopt = IP6CB(pktopts);
475 if (rxopt->srcrt)
476 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt));
477 }
478
479 if (opt && opt->srcrt) {
480 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
481 ipv6_addr_copy(&final, &fl.fl6_dst);
482 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
483 final_p = &final;
484 }
485
486 err = ip6_dst_lookup(sk, &dst, &fl);
487 if (err)
488 goto done;
489 if (final_p)
490 ipv6_addr_copy(&fl.fl6_dst, final_p);
491 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
492 goto done;
493 }
494
495 skb = tcp_make_synack(sk, dst, req);
496 if (skb) {
497 struct tcphdr *th = skb->h.th;
498
499 th->check = tcp_v6_check(th, skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700500 &treq->loc_addr, &treq->rmt_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 csum_partial((char *)th, skb->len, skb->csum));
502
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700503 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 err = ip6_xmit(sk, skb, &fl, opt, 0);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200505 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
507
508done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (opt && opt != np->opt)
510 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800511 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return err;
513}
514
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700515static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800517 if (inet6_rsk(req)->pktopts)
518 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519}
520
David S. Miller9ec75fe2006-11-09 16:26:09 -0800521static struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700523 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700525 .send_ack = tcp_v6_reqsk_send_ack,
526 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 .send_reset = tcp_v6_send_reset
528};
529
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800530static struct timewait_sock_ops tcp6_timewait_sock_ops = {
531 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
532 .twsk_unique = tcp_twsk_unique,
533};
534
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800535static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800538 struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Patrick McHardy84fa7932006-08-29 16:44:56 -0700540 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
542 skb->csum = offsetof(struct tcphdr, check);
543 } else {
544 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
545 csum_partial((char *)th, th->doff<<2,
546 skb->csum));
547 }
548}
549
Herbert Xua430a432006-07-08 13:34:56 -0700550static int tcp_v6_gso_send_check(struct sk_buff *skb)
551{
552 struct ipv6hdr *ipv6h;
553 struct tcphdr *th;
554
555 if (!pskb_may_pull(skb, sizeof(*th)))
556 return -EINVAL;
557
558 ipv6h = skb->nh.ipv6h;
559 th = skb->h.th;
560
561 th->check = 0;
562 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
563 IPPROTO_TCP, 0);
564 skb->csum = offsetof(struct tcphdr, check);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700565 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xua430a432006-07-08 13:34:56 -0700566 return 0;
567}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569static void tcp_v6_send_reset(struct sk_buff *skb)
570{
571 struct tcphdr *th = skb->h.th, *t1;
572 struct sk_buff *buff;
573 struct flowi fl;
574
575 if (th->rst)
576 return;
577
578 if (!ipv6_unicast_destination(skb))
579 return;
580
581 /*
582 * We need to grab some memory, and put together an RST,
583 * and then put it into the queue to be sent.
584 */
585
586 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr),
587 GFP_ATOMIC);
588 if (buff == NULL)
589 return;
590
591 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
592
593 t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
594
595 /* Swap the send and the receive. */
596 memset(t1, 0, sizeof(*t1));
597 t1->dest = th->source;
598 t1->source = th->dest;
599 t1->doff = sizeof(*t1)/4;
600 t1->rst = 1;
601
602 if(th->ack) {
603 t1->seq = th->ack_seq;
604 } else {
605 t1->ack = 1;
606 t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
607 + skb->len - (th->doff<<2));
608 }
609
610 buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
611
612 memset(&fl, 0, sizeof(fl));
613 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
614 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
615
616 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
617 sizeof(*t1), IPPROTO_TCP,
618 buff->csum);
619
620 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300621 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 fl.fl_ip_dport = t1->dest;
623 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700624 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 /* sk = NULL, but it is safe for now. RST socket required. */
627 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
628
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800629 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
David Woodhouseae0f7d52006-01-11 15:53:04 -0800630 ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800631 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
632 TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
636
637 kfree_skb(buff);
638}
639
640static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
641{
642 struct tcphdr *th = skb->h.th, *t1;
643 struct sk_buff *buff;
644 struct flowi fl;
645 int tot_len = sizeof(struct tcphdr);
646
647 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -0700648 tot_len += TCPOLEN_TSTAMP_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
651 GFP_ATOMIC);
652 if (buff == NULL)
653 return;
654
655 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
656
657 t1 = (struct tcphdr *) skb_push(buff,tot_len);
658
659 /* Swap the send and the receive. */
660 memset(t1, 0, sizeof(*t1));
661 t1->dest = th->source;
662 t1->source = th->dest;
663 t1->doff = tot_len/4;
664 t1->seq = htonl(seq);
665 t1->ack_seq = htonl(ack);
666 t1->ack = 1;
667 t1->window = htons(win);
668
669 if (ts) {
670 u32 *ptr = (u32*)(t1 + 1);
671 *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
672 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
673 *ptr++ = htonl(tcp_time_stamp);
674 *ptr = htonl(ts);
675 }
676
677 buff->csum = csum_partial((char *)t1, tot_len, 0);
678
679 memset(&fl, 0, sizeof(fl));
680 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
681 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
682
683 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
684 tot_len, IPPROTO_TCP,
685 buff->csum);
686
687 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300688 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 fl.fl_ip_dport = t1->dest;
690 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700691 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800694 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
David Woodhouseae0f7d52006-01-11 15:53:04 -0800695 ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800696 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 }
700
701 kfree_skb(buff);
702}
703
704static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
705{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700706 struct inet_timewait_sock *tw = inet_twsk(sk);
707 const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700709 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
710 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
711 tcptw->tw_ts_recent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700713 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714}
715
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700716static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700718 tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719}
720
721
722static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
723{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700724 struct request_sock *req, **prev;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300725 const struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 struct sock *nsk;
727
728 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800729 req = inet6_csk_search_req(sk, &prev, th->source,
730 &skb->nh.ipv6h->saddr,
731 &skb->nh.ipv6h->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (req)
733 return tcp_check_req(sk, skb, req, prev);
734
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300735 nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr,
736 th->source, &skb->nh.ipv6h->daddr,
737 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 if (nsk) {
740 if (nsk->sk_state != TCP_TIME_WAIT) {
741 bh_lock_sock(nsk);
742 return nsk;
743 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700744 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return NULL;
746 }
747
748#if 0 /*def CONFIG_SYN_COOKIES*/
749 if (!th->rst && !th->syn && th->ack)
750 sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
751#endif
752 return sk;
753}
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755/* FIXME: this is substantially similar to the ipv4 code.
756 * Can some kind of merge be done? -- erics
757 */
758static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
759{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800760 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 struct ipv6_pinfo *np = inet6_sk(sk);
762 struct tcp_options_received tmp_opt;
763 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700764 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 __u32 isn = TCP_SKB_CB(skb)->when;
766
767 if (skb->protocol == htons(ETH_P_IP))
768 return tcp_v4_conn_request(sk, skb);
769
770 if (!ipv6_unicast_destination(skb))
771 goto drop;
772
773 /*
774 * There are no SYN attacks on IPv6, yet...
775 */
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700776 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 if (net_ratelimit())
778 printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
779 goto drop;
780 }
781
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700782 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 goto drop;
784
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800785 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (req == NULL)
787 goto drop;
788
789 tcp_clear_options(&tmp_opt);
790 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
791 tmp_opt.user_mss = tp->rx_opt.user_mss;
792
793 tcp_parse_options(skb, &tmp_opt, 0);
794
795 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
796 tcp_openreq_init(req, &tmp_opt, skb);
797
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800798 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700799 ipv6_addr_copy(&treq->rmt_addr, &skb->nh.ipv6h->saddr);
800 ipv6_addr_copy(&treq->loc_addr, &skb->nh.ipv6h->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 TCP_ECN_create_request(req, skb->h.th);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700802 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (ipv6_opt_accepted(sk, skb) ||
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900804 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
805 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 atomic_inc(&skb->users);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700807 treq->pktopts = skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700809 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 /* So that link locals have meaning */
812 if (!sk->sk_bound_dev_if &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700813 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300814 treq->iif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 if (isn == 0)
Gerrit Renkera94f7232006-11-10 14:06:49 -0800817 isn = tcp_v6_init_sequence(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700819 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700821 security_inet_conn_request(sk, skb, req);
822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 if (tcp_v6_send_synack(sk, req, NULL))
824 goto drop;
825
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800826 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 return 0;
828
829drop:
830 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700831 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 return 0; /* don't send reset */
834}
835
836static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700837 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 struct dst_entry *dst)
839{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800840 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
842 struct tcp6_sock *newtcp6sk;
843 struct inet_sock *newinet;
844 struct tcp_sock *newtp;
845 struct sock *newsk;
846 struct ipv6_txoptions *opt;
847
848 if (skb->protocol == htons(ETH_P_IP)) {
849 /*
850 * v6 mapped
851 */
852
853 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
854
855 if (newsk == NULL)
856 return NULL;
857
858 newtcp6sk = (struct tcp6_sock *)newsk;
859 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
860
861 newinet = inet_sk(newsk);
862 newnp = inet6_sk(newsk);
863 newtp = tcp_sk(newsk);
864
865 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
866
867 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
868 newinet->daddr);
869
870 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
871 newinet->saddr);
872
873 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
874
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800875 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
877 newnp->pktoptions = NULL;
878 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300879 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
881
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -0700882 /*
883 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
884 * here, tcp_create_openreq_child now does this for us, see the comment in
885 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800889 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 Sync it now.
891 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800892 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894 return newsk;
895 }
896
897 opt = np->opt;
898
899 if (sk_acceptq_is_full(sk))
900 goto out_overflow;
901
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900902 if (np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700903 opt == NULL && treq->pktopts) {
904 struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 if (rxopt->srcrt)
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700906 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr *)(treq->pktopts->nh.raw + rxopt->srcrt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908
909 if (dst == NULL) {
910 struct in6_addr *final_p = NULL, final;
911 struct flowi fl;
912
913 memset(&fl, 0, sizeof(fl));
914 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700915 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 if (opt && opt->srcrt) {
917 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
918 ipv6_addr_copy(&final, &fl.fl6_dst);
919 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
920 final_p = &final;
921 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700922 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700924 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700926 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 if (ip6_dst_lookup(sk, &dst, &fl))
929 goto out;
930
931 if (final_p)
932 ipv6_addr_copy(&fl.fl6_dst, final_p);
933
934 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
935 goto out;
936 }
937
938 newsk = tcp_create_openreq_child(sk, req, skb);
939 if (newsk == NULL)
940 goto out;
941
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -0700942 /*
943 * No need to charge this sock to the relevant IPv6 refcnt debug socks
944 * count here, tcp_create_openreq_child now does this for us, see the
945 * comment in that function for the gory details. -acme
946 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Stephen Hemminger59eed272006-08-25 15:55:43 -0700948 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700949 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 newtcp6sk = (struct tcp6_sock *)newsk;
952 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
953
954 newtp = tcp_sk(newsk);
955 newinet = inet_sk(newsk);
956 newnp = inet6_sk(newsk);
957
958 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
959
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700960 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
961 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
962 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
963 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 /* Now IPv6 options...
966
967 First: no IPv4 options.
968 */
969 newinet->opt = NULL;
970
971 /* Clone RX bits */
972 newnp->rxopt.all = np->rxopt.all;
973
974 /* Clone pktoptions received with SYN */
975 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700976 if (treq->pktopts != NULL) {
977 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
978 kfree_skb(treq->pktopts);
979 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (newnp->pktoptions)
981 skb_set_owner_r(newnp->pktoptions, newsk);
982 }
983 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300984 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
986
987 /* Clone native IPv6 options from listening socket (if any)
988
989 Yes, keeping reference count would be much more clever,
990 but we make one more one thing there: reattach optmem
991 to newsk.
992 */
993 if (opt) {
994 newnp->opt = ipv6_dup_options(newsk, opt);
995 if (opt != np->opt)
996 sock_kfree_s(sk, opt, opt->tot_len);
997 }
998
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800999 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001001 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1002 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
John Heffner5d424d52006-03-20 17:53:41 -08001004 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 tcp_sync_mss(newsk, dst_mtu(dst));
1006 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1007 tcp_initialize_rcv_mss(newsk);
1008
1009 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
1010
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -08001011 __inet6_hash(&tcp_hashinfo, newsk);
Arnaldo Carvalho de Melo2d8c4ce2005-08-09 20:07:13 -07001012 inet_inherit_port(&tcp_hashinfo, sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 return newsk;
1015
1016out_overflow:
1017 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
1018out:
1019 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
1020 if (opt && opt != np->opt)
1021 sock_kfree_s(sk, opt, opt->tot_len);
1022 dst_release(dst);
1023 return NULL;
1024}
1025
1026static int tcp_v6_checksum_init(struct sk_buff *skb)
1027{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001028 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
Herbert Xufb286bb2005-11-10 13:01:24 -08001030 &skb->nh.ipv6h->daddr,skb->csum)) {
1031 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001035
1036 skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
1037 &skb->nh.ipv6h->daddr, 0);
1038
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001040 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 }
1042 return 0;
1043}
1044
1045/* The socket must have it's spinlock held when we get
1046 * here.
1047 *
1048 * We have a potential double-lock case here, so even when
1049 * doing backlog processing we use the BH locking scheme.
1050 * This is because we cannot sleep with the original spinlock
1051 * held.
1052 */
1053static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1054{
1055 struct ipv6_pinfo *np = inet6_sk(sk);
1056 struct tcp_sock *tp;
1057 struct sk_buff *opt_skb = NULL;
1058
1059 /* Imagine: socket is IPv6. IPv4 packet arrives,
1060 goes to IPv4 receive handler and backlogged.
1061 From backlog it always goes here. Kerboom...
1062 Fortunately, tcp_rcv_established and rcv_established
1063 handle them correctly, but it is not case with
1064 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1065 */
1066
1067 if (skb->protocol == htons(ETH_P_IP))
1068 return tcp_v4_do_rcv(sk, skb);
1069
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001070 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 goto discard;
1072
1073 /*
1074 * socket locking is here for SMP purposes as backlog rcv
1075 * is currently called with bh processing disabled.
1076 */
1077
1078 /* Do Stevens' IPV6_PKTOPTIONS.
1079
1080 Yes, guys, it is the only place in our code, where we
1081 may make it not affecting IPv4.
1082 The rest of code is protocol independent,
1083 and I do not like idea to uglify IPv4.
1084
1085 Actually, all the idea behind IPV6_PKTOPTIONS
1086 looks not very well thought. For now we latch
1087 options, received in the last packet, enqueued
1088 by tcp. Feel free to propose better solution.
1089 --ANK (980728)
1090 */
1091 if (np->rxopt.all)
1092 opt_skb = skb_clone(skb, GFP_ATOMIC);
1093
1094 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1095 TCP_CHECK_TIMER(sk);
1096 if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
1097 goto reset;
1098 TCP_CHECK_TIMER(sk);
1099 if (opt_skb)
1100 goto ipv6_pktoptions;
1101 return 0;
1102 }
1103
1104 if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
1105 goto csum_err;
1106
1107 if (sk->sk_state == TCP_LISTEN) {
1108 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1109 if (!nsk)
1110 goto discard;
1111
1112 /*
1113 * Queue it on the new socket if the new socket is active,
1114 * otherwise we just shortcircuit this and continue with
1115 * the new socket..
1116 */
1117 if(nsk != sk) {
1118 if (tcp_child_process(sk, nsk, skb))
1119 goto reset;
1120 if (opt_skb)
1121 __kfree_skb(opt_skb);
1122 return 0;
1123 }
1124 }
1125
1126 TCP_CHECK_TIMER(sk);
1127 if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
1128 goto reset;
1129 TCP_CHECK_TIMER(sk);
1130 if (opt_skb)
1131 goto ipv6_pktoptions;
1132 return 0;
1133
1134reset:
1135 tcp_v6_send_reset(skb);
1136discard:
1137 if (opt_skb)
1138 __kfree_skb(opt_skb);
1139 kfree_skb(skb);
1140 return 0;
1141csum_err:
1142 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1143 goto discard;
1144
1145
1146ipv6_pktoptions:
1147 /* Do you ask, what is it?
1148
1149 1. skb was enqueued by tcp.
1150 2. skb is added to tail of read queue, rather than out of order.
1151 3. socket is not in passive state.
1152 4. Finally, it really contains options, which user wants to receive.
1153 */
1154 tp = tcp_sk(sk);
1155 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1156 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001157 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001158 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001159 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
1161 if (ipv6_opt_accepted(sk, opt_skb)) {
1162 skb_set_owner_r(opt_skb, sk);
1163 opt_skb = xchg(&np->pktoptions, opt_skb);
1164 } else {
1165 __kfree_skb(opt_skb);
1166 opt_skb = xchg(&np->pktoptions, NULL);
1167 }
1168 }
1169
1170 if (opt_skb)
1171 kfree_skb(opt_skb);
1172 return 0;
1173}
1174
Patrick McHardy951dbc82006-01-06 23:02:34 -08001175static int tcp_v6_rcv(struct sk_buff **pskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
1177 struct sk_buff *skb = *pskb;
1178 struct tcphdr *th;
1179 struct sock *sk;
1180 int ret;
1181
1182 if (skb->pkt_type != PACKET_HOST)
1183 goto discard_it;
1184
1185 /*
1186 * Count it even if it's bad.
1187 */
1188 TCP_INC_STATS_BH(TCP_MIB_INSEGS);
1189
1190 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1191 goto discard_it;
1192
1193 th = skb->h.th;
1194
1195 if (th->doff < sizeof(struct tcphdr)/4)
1196 goto bad_packet;
1197 if (!pskb_may_pull(skb, th->doff*4))
1198 goto discard_it;
1199
1200 if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
Herbert Xufb286bb2005-11-10 13:01:24 -08001201 tcp_v6_checksum_init(skb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 goto bad_packet;
1203
1204 th = skb->h.th;
1205 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1206 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1207 skb->len - th->doff*4);
1208 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1209 TCP_SKB_CB(skb)->when = 0;
1210 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
1211 TCP_SKB_CB(skb)->sacked = 0;
1212
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001213 sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source,
1214 &skb->nh.ipv6h->daddr, ntohs(th->dest),
1215 inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217 if (!sk)
1218 goto no_tcp_socket;
1219
1220process:
1221 if (sk->sk_state == TCP_TIME_WAIT)
1222 goto do_time_wait;
1223
1224 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1225 goto discard_and_relse;
1226
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001227 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 goto discard_and_relse;
1229
1230 skb->dev = NULL;
1231
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001232 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 ret = 0;
1234 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001235#ifdef CONFIG_NET_DMA
1236 struct tcp_sock *tp = tcp_sk(sk);
1237 if (tp->ucopy.dma_chan)
1238 ret = tcp_v6_do_rcv(sk, skb);
1239 else
1240#endif
1241 {
1242 if (!tcp_prequeue(sk, skb))
1243 ret = tcp_v6_do_rcv(sk, skb);
1244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 } else
1246 sk_add_backlog(sk, skb);
1247 bh_unlock_sock(sk);
1248
1249 sock_put(sk);
1250 return ret ? -1 : 0;
1251
1252no_tcp_socket:
1253 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1254 goto discard_it;
1255
1256 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1257bad_packet:
1258 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1259 } else {
1260 tcp_v6_send_reset(skb);
1261 }
1262
1263discard_it:
1264
1265 /*
1266 * Discard frame
1267 */
1268
1269 kfree_skb(skb);
1270 return 0;
1271
1272discard_and_relse:
1273 sock_put(sk);
1274 goto discard_it;
1275
1276do_time_wait:
1277 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001278 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 goto discard_it;
1280 }
1281
1282 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1283 TCP_INC_STATS_BH(TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001284 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 goto discard_it;
1286 }
1287
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001288 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 case TCP_TW_SYN:
1290 {
1291 struct sock *sk2;
1292
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001293 sk2 = inet6_lookup_listener(&tcp_hashinfo,
1294 &skb->nh.ipv6h->daddr,
1295 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001297 struct inet_timewait_sock *tw = inet_twsk(sk);
1298 inet_twsk_deschedule(tw, &tcp_death_row);
1299 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 sk = sk2;
1301 goto process;
1302 }
1303 /* Fall through to ACK */
1304 }
1305 case TCP_TW_ACK:
1306 tcp_v6_timewait_ack(sk, skb);
1307 break;
1308 case TCP_TW_RST:
1309 goto no_tcp_socket;
1310 case TCP_TW_SUCCESS:;
1311 }
1312 goto discard_it;
1313}
1314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315static int tcp_v6_remember_stamp(struct sock *sk)
1316{
1317 /* Alas, not yet... */
1318 return 0;
1319}
1320
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001321static struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001322 .queue_xmit = inet6_csk_xmit,
1323 .send_check = tcp_v6_send_check,
1324 .rebuild_header = inet6_sk_rebuild_header,
1325 .conn_request = tcp_v6_conn_request,
1326 .syn_recv_sock = tcp_v6_syn_recv_sock,
1327 .remember_stamp = tcp_v6_remember_stamp,
1328 .net_header_len = sizeof(struct ipv6hdr),
1329 .setsockopt = ipv6_setsockopt,
1330 .getsockopt = ipv6_getsockopt,
1331 .addr2sockaddr = inet6_csk_addr2sockaddr,
1332 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001333#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001334 .compat_setsockopt = compat_ipv6_setsockopt,
1335 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001336#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337};
1338
1339/*
1340 * TCP over IPv4 via INET6 API
1341 */
1342
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001343static struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001344 .queue_xmit = ip_queue_xmit,
1345 .send_check = tcp_v4_send_check,
1346 .rebuild_header = inet_sk_rebuild_header,
1347 .conn_request = tcp_v6_conn_request,
1348 .syn_recv_sock = tcp_v6_syn_recv_sock,
1349 .remember_stamp = tcp_v4_remember_stamp,
1350 .net_header_len = sizeof(struct iphdr),
1351 .setsockopt = ipv6_setsockopt,
1352 .getsockopt = ipv6_getsockopt,
1353 .addr2sockaddr = inet6_csk_addr2sockaddr,
1354 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001355#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001356 .compat_setsockopt = compat_ipv6_setsockopt,
1357 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001358#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359};
1360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361/* NOTE: A lot of things set to zero explicitly by call to
1362 * sk_alloc() so need not be done here.
1363 */
1364static int tcp_v6_init_sock(struct sock *sk)
1365{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001366 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 struct tcp_sock *tp = tcp_sk(sk);
1368
1369 skb_queue_head_init(&tp->out_of_order_queue);
1370 tcp_init_xmit_timers(sk);
1371 tcp_prequeue_init(tp);
1372
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001373 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 tp->mdev = TCP_TIMEOUT_INIT;
1375
1376 /* So many TCP implementations out there (incorrectly) count the
1377 * initial SYN frame in their delayed-ACK and congestion control
1378 * algorithms that we must have the following bandaid to talk
1379 * efficiently to them. -DaveM
1380 */
1381 tp->snd_cwnd = 2;
1382
1383 /* See draft-stevens-tcpca-spec-01 for discussion of the
1384 * initialization of these values.
1385 */
1386 tp->snd_ssthresh = 0x7fffffff;
1387 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001388 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 tp->reordering = sysctl_tcp_reordering;
1391
1392 sk->sk_state = TCP_CLOSE;
1393
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001394 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001395 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001396 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 sk->sk_write_space = sk_stream_write_space;
1398 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1399
1400 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1401 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1402
1403 atomic_inc(&tcp_sockets_allocated);
1404
1405 return 0;
1406}
1407
1408static int tcp_v6_destroy_sock(struct sock *sk)
1409{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 tcp_v4_destroy_sock(sk);
1411 return inet6_destroy_sock(sk);
1412}
1413
1414/* Proc filesystem TCPv6 sock list dumping. */
1415static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001416 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001419 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1420 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
1422 if (ttd < 0)
1423 ttd = 0;
1424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 seq_printf(seq,
1426 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1427 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1428 i,
1429 src->s6_addr32[0], src->s6_addr32[1],
1430 src->s6_addr32[2], src->s6_addr32[3],
1431 ntohs(inet_sk(sk)->sport),
1432 dest->s6_addr32[0], dest->s6_addr32[1],
1433 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001434 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 TCP_SYN_RECV,
1436 0,0, /* could print option size, but that is af dependent. */
1437 1, /* timers active (only the expire timer) */
1438 jiffies_to_clock_t(ttd),
1439 req->retrans,
1440 uid,
1441 0, /* non standard timer */
1442 0, /* open_requests have no inode */
1443 0, req);
1444}
1445
1446static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1447{
1448 struct in6_addr *dest, *src;
1449 __u16 destp, srcp;
1450 int timer_active;
1451 unsigned long timer_expires;
1452 struct inet_sock *inet = inet_sk(sp);
1453 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001454 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 struct ipv6_pinfo *np = inet6_sk(sp);
1456
1457 dest = &np->daddr;
1458 src = &np->rcv_saddr;
1459 destp = ntohs(inet->dport);
1460 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001461
1462 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001464 timer_expires = icsk->icsk_timeout;
1465 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001467 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 } else if (timer_pending(&sp->sk_timer)) {
1469 timer_active = 2;
1470 timer_expires = sp->sk_timer.expires;
1471 } else {
1472 timer_active = 0;
1473 timer_expires = jiffies;
1474 }
1475
1476 seq_printf(seq,
1477 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1478 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
1479 i,
1480 src->s6_addr32[0], src->s6_addr32[1],
1481 src->s6_addr32[2], src->s6_addr32[3], srcp,
1482 dest->s6_addr32[0], dest->s6_addr32[1],
1483 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1484 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07001485 tp->write_seq-tp->snd_una,
1486 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 timer_active,
1488 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001489 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001491 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 sock_i_ino(sp),
1493 atomic_read(&sp->sk_refcnt), sp,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001494 icsk->icsk_rto,
1495 icsk->icsk_ack.ato,
1496 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
1498 );
1499}
1500
1501static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001502 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503{
1504 struct in6_addr *dest, *src;
1505 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001506 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 int ttd = tw->tw_ttd - jiffies;
1508
1509 if (ttd < 0)
1510 ttd = 0;
1511
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001512 dest = &tw6->tw_v6_daddr;
1513 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 destp = ntohs(tw->tw_dport);
1515 srcp = ntohs(tw->tw_sport);
1516
1517 seq_printf(seq,
1518 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1519 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1520 i,
1521 src->s6_addr32[0], src->s6_addr32[1],
1522 src->s6_addr32[2], src->s6_addr32[3], srcp,
1523 dest->s6_addr32[0], dest->s6_addr32[1],
1524 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1525 tw->tw_substate, 0, 0,
1526 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1527 atomic_read(&tw->tw_refcnt), tw);
1528}
1529
1530#ifdef CONFIG_PROC_FS
1531static int tcp6_seq_show(struct seq_file *seq, void *v)
1532{
1533 struct tcp_iter_state *st;
1534
1535 if (v == SEQ_START_TOKEN) {
1536 seq_puts(seq,
1537 " sl "
1538 "local_address "
1539 "remote_address "
1540 "st tx_queue rx_queue tr tm->when retrnsmt"
1541 " uid timeout inode\n");
1542 goto out;
1543 }
1544 st = seq->private;
1545
1546 switch (st->state) {
1547 case TCP_SEQ_STATE_LISTENING:
1548 case TCP_SEQ_STATE_ESTABLISHED:
1549 get_tcp6_sock(seq, v, st->num);
1550 break;
1551 case TCP_SEQ_STATE_OPENREQ:
1552 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
1553 break;
1554 case TCP_SEQ_STATE_TIME_WAIT:
1555 get_timewait6_sock(seq, v, st->num);
1556 break;
1557 }
1558out:
1559 return 0;
1560}
1561
1562static struct file_operations tcp6_seq_fops;
1563static struct tcp_seq_afinfo tcp6_seq_afinfo = {
1564 .owner = THIS_MODULE,
1565 .name = "tcp6",
1566 .family = AF_INET6,
1567 .seq_show = tcp6_seq_show,
1568 .seq_fops = &tcp6_seq_fops,
1569};
1570
1571int __init tcp6_proc_init(void)
1572{
1573 return tcp_proc_register(&tcp6_seq_afinfo);
1574}
1575
1576void tcp6_proc_exit(void)
1577{
1578 tcp_proc_unregister(&tcp6_seq_afinfo);
1579}
1580#endif
1581
1582struct proto tcpv6_prot = {
1583 .name = "TCPv6",
1584 .owner = THIS_MODULE,
1585 .close = tcp_close,
1586 .connect = tcp_v6_connect,
1587 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001588 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 .ioctl = tcp_ioctl,
1590 .init = tcp_v6_init_sock,
1591 .destroy = tcp_v6_destroy_sock,
1592 .shutdown = tcp_shutdown,
1593 .setsockopt = tcp_setsockopt,
1594 .getsockopt = tcp_getsockopt,
1595 .sendmsg = tcp_sendmsg,
1596 .recvmsg = tcp_recvmsg,
1597 .backlog_rcv = tcp_v6_do_rcv,
1598 .hash = tcp_v6_hash,
1599 .unhash = tcp_unhash,
1600 .get_port = tcp_v6_get_port,
1601 .enter_memory_pressure = tcp_enter_memory_pressure,
1602 .sockets_allocated = &tcp_sockets_allocated,
1603 .memory_allocated = &tcp_memory_allocated,
1604 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07001605 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 .sysctl_mem = sysctl_tcp_mem,
1607 .sysctl_wmem = sysctl_tcp_wmem,
1608 .sysctl_rmem = sysctl_tcp_rmem,
1609 .max_header = MAX_TCP_HEADER,
1610 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08001611 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001612 .rsk_prot = &tcp6_request_sock_ops,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001613#ifdef CONFIG_COMPAT
1614 .compat_setsockopt = compat_tcp_setsockopt,
1615 .compat_getsockopt = compat_tcp_getsockopt,
1616#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617};
1618
1619static struct inet6_protocol tcpv6_protocol = {
1620 .handler = tcp_v6_rcv,
1621 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07001622 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07001623 .gso_segment = tcp_tso_segment,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1625};
1626
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627static struct inet_protosw tcpv6_protosw = {
1628 .type = SOCK_STREAM,
1629 .protocol = IPPROTO_TCP,
1630 .prot = &tcpv6_prot,
1631 .ops = &inet6_stream_ops,
1632 .capability = -1,
1633 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001634 .flags = INET_PROTOSW_PERMANENT |
1635 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636};
1637
1638void __init tcpv6_init(void)
1639{
1640 /* register inet6 protocol */
1641 if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
1642 printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
1643 inet6_register_protosw(&tcpv6_protosw);
David Woodhouseae0f7d52006-01-11 15:53:04 -08001644
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08001645 if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW,
1646 IPPROTO_TCP) < 0)
David Woodhouseae0f7d52006-01-11 15:53:04 -08001647 panic("Failed to create the TCPv6 control socket.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648}