blob: 5bdcb9002cf733ee670c05d12e2801e3a9488302 [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
109static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
110{
111 if (skb->protocol == htons(ETH_P_IPV6)) {
112 return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
113 skb->nh.ipv6h->saddr.s6_addr32,
114 skb->h.th->dest,
115 skb->h.th->source);
116 } else {
117 return secure_tcp_sequence_number(skb->nh.iph->daddr,
118 skb->nh.iph->saddr,
119 skb->h.th->dest,
120 skb->h.th->source);
121 }
122}
123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
125 int addr_len)
126{
127 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800128 struct inet_sock *inet = inet_sk(sk);
129 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct ipv6_pinfo *np = inet6_sk(sk);
131 struct tcp_sock *tp = tcp_sk(sk);
132 struct in6_addr *saddr = NULL, *final_p = NULL, final;
133 struct flowi fl;
134 struct dst_entry *dst;
135 int addr_type;
136 int err;
137
138 if (addr_len < SIN6_LEN_RFC2133)
139 return -EINVAL;
140
141 if (usin->sin6_family != AF_INET6)
142 return(-EAFNOSUPPORT);
143
144 memset(&fl, 0, sizeof(fl));
145
146 if (np->sndflow) {
147 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
148 IP6_ECN_flow_init(fl.fl6_flowlabel);
149 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
150 struct ip6_flowlabel *flowlabel;
151 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
152 if (flowlabel == NULL)
153 return -EINVAL;
154 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
155 fl6_sock_release(flowlabel);
156 }
157 }
158
159 /*
160 * connect() to INADDR_ANY means loopback (BSD'ism).
161 */
162
163 if(ipv6_addr_any(&usin->sin6_addr))
164 usin->sin6_addr.s6_addr[15] = 0x1;
165
166 addr_type = ipv6_addr_type(&usin->sin6_addr);
167
168 if(addr_type & IPV6_ADDR_MULTICAST)
169 return -ENETUNREACH;
170
171 if (addr_type&IPV6_ADDR_LINKLOCAL) {
172 if (addr_len >= sizeof(struct sockaddr_in6) &&
173 usin->sin6_scope_id) {
174 /* If interface is set while binding, indices
175 * must coincide.
176 */
177 if (sk->sk_bound_dev_if &&
178 sk->sk_bound_dev_if != usin->sin6_scope_id)
179 return -EINVAL;
180
181 sk->sk_bound_dev_if = usin->sin6_scope_id;
182 }
183
184 /* Connect to link-local address requires an interface */
185 if (!sk->sk_bound_dev_if)
186 return -EINVAL;
187 }
188
189 if (tp->rx_opt.ts_recent_stamp &&
190 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
191 tp->rx_opt.ts_recent = 0;
192 tp->rx_opt.ts_recent_stamp = 0;
193 tp->write_seq = 0;
194 }
195
196 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
197 np->flow_label = fl.fl6_flowlabel;
198
199 /*
200 * TCP over IPv4
201 */
202
203 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800204 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 struct sockaddr_in sin;
206
207 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
208
209 if (__ipv6_only_sock(sk))
210 return -ENETUNREACH;
211
212 sin.sin_family = AF_INET;
213 sin.sin_port = usin->sin6_port;
214 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
215
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800216 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 sk->sk_backlog_rcv = tcp_v4_do_rcv;
218
219 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
220
221 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800222 icsk->icsk_ext_hdr_len = exthdrlen;
223 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 sk->sk_backlog_rcv = tcp_v6_do_rcv;
225 goto failure;
226 } else {
227 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
228 inet->saddr);
229 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
230 inet->rcv_saddr);
231 }
232
233 return err;
234 }
235
236 if (!ipv6_addr_any(&np->rcv_saddr))
237 saddr = &np->rcv_saddr;
238
239 fl.proto = IPPROTO_TCP;
240 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
241 ipv6_addr_copy(&fl.fl6_src,
242 (saddr ? saddr : &np->saddr));
243 fl.oif = sk->sk_bound_dev_if;
244 fl.fl_ip_dport = usin->sin6_port;
245 fl.fl_ip_sport = inet->sport;
246
247 if (np->opt && np->opt->srcrt) {
248 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
249 ipv6_addr_copy(&final, &fl.fl6_dst);
250 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
251 final_p = &final;
252 }
253
254 err = ip6_dst_lookup(sk, &dst, &fl);
255 if (err)
256 goto failure;
257 if (final_p)
258 ipv6_addr_copy(&fl.fl6_dst, final_p);
259
Patrick McHardye1044112005-09-08 15:11:55 -0700260 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263 if (saddr == NULL) {
264 saddr = &fl.fl6_src;
265 ipv6_addr_copy(&np->rcv_saddr, saddr);
266 }
267
268 /* set the source address */
269 ipv6_addr_copy(&np->saddr, saddr);
270 inet->rcv_saddr = LOOPBACK4_IPV6;
271
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700272 sk->sk_gso_type = SKB_GSO_TCPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 ip6_dst_store(sk, dst, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800275 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800277 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
278 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
281
282 inet->dport = usin->sin6_port;
283
284 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800285 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 if (err)
287 goto late_failure;
288
289 if (!tp->write_seq)
290 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
291 np->daddr.s6_addr32,
292 inet->sport,
293 inet->dport);
294
295 err = tcp_connect(sk);
296 if (err)
297 goto late_failure;
298
299 return 0;
300
301late_failure:
302 tcp_set_state(sk, TCP_CLOSE);
303 __sk_dst_reset(sk);
304failure:
305 inet->dport = 0;
306 sk->sk_route_caps = 0;
307 return err;
308}
309
310static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
311 int type, int code, int offset, __u32 info)
312{
313 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300314 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 struct ipv6_pinfo *np;
316 struct sock *sk;
317 int err;
318 struct tcp_sock *tp;
319 __u32 seq;
320
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300321 sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
322 th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 if (sk == NULL) {
325 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
326 return;
327 }
328
329 if (sk->sk_state == TCP_TIME_WAIT) {
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700330 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 return;
332 }
333
334 bh_lock_sock(sk);
335 if (sock_owned_by_user(sk))
336 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
337
338 if (sk->sk_state == TCP_CLOSE)
339 goto out;
340
341 tp = tcp_sk(sk);
342 seq = ntohl(th->seq);
343 if (sk->sk_state != TCP_LISTEN &&
344 !between(seq, tp->snd_una, tp->snd_nxt)) {
345 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
346 goto out;
347 }
348
349 np = inet6_sk(sk);
350
351 if (type == ICMPV6_PKT_TOOBIG) {
352 struct dst_entry *dst = NULL;
353
354 if (sock_owned_by_user(sk))
355 goto out;
356 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
357 goto out;
358
359 /* icmp should have updated the destination cache entry */
360 dst = __sk_dst_check(sk, np->dst_cookie);
361
362 if (dst == NULL) {
363 struct inet_sock *inet = inet_sk(sk);
364 struct flowi fl;
365
366 /* BUGGG_FUTURE: Again, it is not clear how
367 to handle rthdr case. Ignore this complexity
368 for now.
369 */
370 memset(&fl, 0, sizeof(fl));
371 fl.proto = IPPROTO_TCP;
372 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
373 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
374 fl.oif = sk->sk_bound_dev_if;
375 fl.fl_ip_dport = inet->dport;
376 fl.fl_ip_sport = inet->sport;
377
378 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
379 sk->sk_err_soft = -err;
380 goto out;
381 }
382
383 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
384 sk->sk_err_soft = -err;
385 goto out;
386 }
387
388 } else
389 dst_hold(dst);
390
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800391 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 tcp_sync_mss(sk, dst_mtu(dst));
393 tcp_simple_retransmit(sk);
394 } /* else let the usual retransmit timer handle it */
395 dst_release(dst);
396 goto out;
397 }
398
399 icmpv6_err_convert(type, code, &err);
400
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700401 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700403 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 case TCP_LISTEN:
405 if (sock_owned_by_user(sk))
406 goto out;
407
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800408 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
409 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (!req)
411 goto out;
412
413 /* ICMPs are not backlogged, hence we cannot get
414 * an established socket here.
415 */
416 BUG_TRAP(req->sk == NULL);
417
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700418 if (seq != tcp_rsk(req)->snt_isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
420 goto out;
421 }
422
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700423 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 goto out;
425
426 case TCP_SYN_SENT:
427 case TCP_SYN_RECV: /* Cannot happen.
428 It can, it SYNs are crossed. --ANK */
429 if (!sock_owned_by_user(sk)) {
430 TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
431 sk->sk_err = err;
432 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
433
434 tcp_done(sk);
435 } else
436 sk->sk_err_soft = err;
437 goto out;
438 }
439
440 if (!sock_owned_by_user(sk) && np->recverr) {
441 sk->sk_err = err;
442 sk->sk_error_report(sk);
443 } else
444 sk->sk_err_soft = err;
445
446out:
447 bh_unlock_sock(sk);
448 sock_put(sk);
449}
450
451
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700452static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 struct dst_entry *dst)
454{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800455 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 struct ipv6_pinfo *np = inet6_sk(sk);
457 struct sk_buff * skb;
458 struct ipv6_txoptions *opt = NULL;
459 struct in6_addr * final_p = NULL, final;
460 struct flowi fl;
461 int err = -1;
462
463 memset(&fl, 0, sizeof(fl));
464 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700465 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
466 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700468 fl.oif = treq->iif;
469 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 fl.fl_ip_sport = inet_sk(sk)->sport;
471
472 if (dst == NULL) {
473 opt = np->opt;
474 if (opt == NULL &&
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900475 np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700476 treq->pktopts) {
477 struct sk_buff *pktopts = treq->pktopts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 struct inet6_skb_parm *rxopt = IP6CB(pktopts);
479 if (rxopt->srcrt)
480 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt));
481 }
482
483 if (opt && opt->srcrt) {
484 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
485 ipv6_addr_copy(&final, &fl.fl6_dst);
486 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
487 final_p = &final;
488 }
489
490 err = ip6_dst_lookup(sk, &dst, &fl);
491 if (err)
492 goto done;
493 if (final_p)
494 ipv6_addr_copy(&fl.fl6_dst, final_p);
495 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
496 goto done;
497 }
498
499 skb = tcp_make_synack(sk, dst, req);
500 if (skb) {
501 struct tcphdr *th = skb->h.th;
502
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);
509 if (err == NET_XMIT_CN)
510 err = 0;
511 }
512
513done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (opt && opt != np->opt)
515 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800516 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 return err;
518}
519
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700520static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800522 if (inet6_rsk(req)->pktopts)
523 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700526static struct request_sock_ops tcp6_request_sock_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700528 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700530 .send_ack = tcp_v6_reqsk_send_ack,
531 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 .send_reset = tcp_v6_send_reset
533};
534
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800535static struct timewait_sock_ops tcp6_timewait_sock_ops = {
536 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
537 .twsk_unique = tcp_twsk_unique,
538};
539
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800540static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
542 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800543 struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 if (skb->ip_summed == CHECKSUM_HW) {
546 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
547 skb->csum = offsetof(struct tcphdr, check);
548 } else {
549 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
550 csum_partial((char *)th, th->doff<<2,
551 skb->csum));
552 }
553}
554
555
556static void tcp_v6_send_reset(struct sk_buff *skb)
557{
558 struct tcphdr *th = skb->h.th, *t1;
559 struct sk_buff *buff;
560 struct flowi fl;
561
562 if (th->rst)
563 return;
564
565 if (!ipv6_unicast_destination(skb))
566 return;
567
568 /*
569 * We need to grab some memory, and put together an RST,
570 * and then put it into the queue to be sent.
571 */
572
573 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr),
574 GFP_ATOMIC);
575 if (buff == NULL)
576 return;
577
578 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
579
580 t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
581
582 /* Swap the send and the receive. */
583 memset(t1, 0, sizeof(*t1));
584 t1->dest = th->source;
585 t1->source = th->dest;
586 t1->doff = sizeof(*t1)/4;
587 t1->rst = 1;
588
589 if(th->ack) {
590 t1->seq = th->ack_seq;
591 } else {
592 t1->ack = 1;
593 t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
594 + skb->len - (th->doff<<2));
595 }
596
597 buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
598
599 memset(&fl, 0, sizeof(fl));
600 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
601 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
602
603 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
604 sizeof(*t1), IPPROTO_TCP,
605 buff->csum);
606
607 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300608 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 fl.fl_ip_dport = t1->dest;
610 fl.fl_ip_sport = t1->source;
611
612 /* sk = NULL, but it is safe for now. RST socket required. */
613 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
614
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800615 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
David Woodhouseae0f7d52006-01-11 15:53:04 -0800616 ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800617 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
618 TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 }
622
623 kfree_skb(buff);
624}
625
626static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
627{
628 struct tcphdr *th = skb->h.th, *t1;
629 struct sk_buff *buff;
630 struct flowi fl;
631 int tot_len = sizeof(struct tcphdr);
632
633 if (ts)
634 tot_len += 3*4;
635
636 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
637 GFP_ATOMIC);
638 if (buff == NULL)
639 return;
640
641 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
642
643 t1 = (struct tcphdr *) skb_push(buff,tot_len);
644
645 /* Swap the send and the receive. */
646 memset(t1, 0, sizeof(*t1));
647 t1->dest = th->source;
648 t1->source = th->dest;
649 t1->doff = tot_len/4;
650 t1->seq = htonl(seq);
651 t1->ack_seq = htonl(ack);
652 t1->ack = 1;
653 t1->window = htons(win);
654
655 if (ts) {
656 u32 *ptr = (u32*)(t1 + 1);
657 *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
658 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
659 *ptr++ = htonl(tcp_time_stamp);
660 *ptr = htonl(ts);
661 }
662
663 buff->csum = csum_partial((char *)t1, tot_len, 0);
664
665 memset(&fl, 0, sizeof(fl));
666 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
667 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
668
669 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
670 tot_len, IPPROTO_TCP,
671 buff->csum);
672
673 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300674 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 fl.fl_ip_dport = t1->dest;
676 fl.fl_ip_sport = t1->source;
677
678 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800679 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
David Woodhouseae0f7d52006-01-11 15:53:04 -0800680 ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800681 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685
686 kfree_skb(buff);
687}
688
689static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
690{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700691 struct inet_timewait_sock *tw = inet_twsk(sk);
692 const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700694 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
695 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
696 tcptw->tw_ts_recent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700698 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699}
700
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700701static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700703 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 -0700704}
705
706
707static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
708{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700709 struct request_sock *req, **prev;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300710 const struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 struct sock *nsk;
712
713 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800714 req = inet6_csk_search_req(sk, &prev, th->source,
715 &skb->nh.ipv6h->saddr,
716 &skb->nh.ipv6h->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 if (req)
718 return tcp_check_req(sk, skb, req, prev);
719
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300720 nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr,
721 th->source, &skb->nh.ipv6h->daddr,
722 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 if (nsk) {
725 if (nsk->sk_state != TCP_TIME_WAIT) {
726 bh_lock_sock(nsk);
727 return nsk;
728 }
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700729 inet_twsk_put((struct inet_timewait_sock *)nsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return NULL;
731 }
732
733#if 0 /*def CONFIG_SYN_COOKIES*/
734 if (!th->rst && !th->syn && th->ack)
735 sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
736#endif
737 return sk;
738}
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740/* FIXME: this is substantially similar to the ipv4 code.
741 * Can some kind of merge be done? -- erics
742 */
743static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
744{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800745 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 struct ipv6_pinfo *np = inet6_sk(sk);
747 struct tcp_options_received tmp_opt;
748 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700749 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 __u32 isn = TCP_SKB_CB(skb)->when;
751
752 if (skb->protocol == htons(ETH_P_IP))
753 return tcp_v4_conn_request(sk, skb);
754
755 if (!ipv6_unicast_destination(skb))
756 goto drop;
757
758 /*
759 * There are no SYN attacks on IPv6, yet...
760 */
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700761 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (net_ratelimit())
763 printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
764 goto drop;
765 }
766
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700767 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 goto drop;
769
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800770 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 if (req == NULL)
772 goto drop;
773
774 tcp_clear_options(&tmp_opt);
775 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
776 tmp_opt.user_mss = tp->rx_opt.user_mss;
777
778 tcp_parse_options(skb, &tmp_opt, 0);
779
780 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
781 tcp_openreq_init(req, &tmp_opt, skb);
782
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800783 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700784 ipv6_addr_copy(&treq->rmt_addr, &skb->nh.ipv6h->saddr);
785 ipv6_addr_copy(&treq->loc_addr, &skb->nh.ipv6h->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 TCP_ECN_create_request(req, skb->h.th);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700787 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if (ipv6_opt_accepted(sk, skb) ||
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900789 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
790 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 atomic_inc(&skb->users);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700792 treq->pktopts = skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700794 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 /* So that link locals have meaning */
797 if (!sk->sk_bound_dev_if &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700798 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300799 treq->iif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 if (isn == 0)
802 isn = tcp_v6_init_sequence(sk,skb);
803
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700804 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 if (tcp_v6_send_synack(sk, req, NULL))
807 goto drop;
808
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800809 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return 0;
811
812drop:
813 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700814 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
817 return 0; /* don't send reset */
818}
819
820static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700821 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 struct dst_entry *dst)
823{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800824 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
826 struct tcp6_sock *newtcp6sk;
827 struct inet_sock *newinet;
828 struct tcp_sock *newtp;
829 struct sock *newsk;
830 struct ipv6_txoptions *opt;
831
832 if (skb->protocol == htons(ETH_P_IP)) {
833 /*
834 * v6 mapped
835 */
836
837 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
838
839 if (newsk == NULL)
840 return NULL;
841
842 newtcp6sk = (struct tcp6_sock *)newsk;
843 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
844
845 newinet = inet_sk(newsk);
846 newnp = inet6_sk(newsk);
847 newtp = tcp_sk(newsk);
848
849 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
850
851 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
852 newinet->daddr);
853
854 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
855 newinet->saddr);
856
857 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
858
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800859 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
861 newnp->pktoptions = NULL;
862 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300863 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
865
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -0700866 /*
867 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
868 * here, tcp_create_openreq_child now does this for us, see the comment in
869 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
872 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800873 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 Sync it now.
875 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800876 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
878 return newsk;
879 }
880
881 opt = np->opt;
882
883 if (sk_acceptq_is_full(sk))
884 goto out_overflow;
885
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900886 if (np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700887 opt == NULL && treq->pktopts) {
888 struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if (rxopt->srcrt)
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700890 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr *)(treq->pktopts->nh.raw + rxopt->srcrt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
892
893 if (dst == NULL) {
894 struct in6_addr *final_p = NULL, final;
895 struct flowi fl;
896
897 memset(&fl, 0, sizeof(fl));
898 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700899 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 if (opt && opt->srcrt) {
901 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
902 ipv6_addr_copy(&final, &fl.fl6_dst);
903 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
904 final_p = &final;
905 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700906 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700908 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 fl.fl_ip_sport = inet_sk(sk)->sport;
910
911 if (ip6_dst_lookup(sk, &dst, &fl))
912 goto out;
913
914 if (final_p)
915 ipv6_addr_copy(&fl.fl6_dst, final_p);
916
917 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
918 goto out;
919 }
920
921 newsk = tcp_create_openreq_child(sk, req, skb);
922 if (newsk == NULL)
923 goto out;
924
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -0700925 /*
926 * No need to charge this sock to the relevant IPv6 refcnt debug socks
927 * count here, tcp_create_openreq_child now does this for us, see the
928 * comment in that function for the gory details. -acme
929 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700931 sk->sk_gso_type = SKB_GSO_TCPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 ip6_dst_store(newsk, dst, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 newtcp6sk = (struct tcp6_sock *)newsk;
935 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
936
937 newtp = tcp_sk(newsk);
938 newinet = inet_sk(newsk);
939 newnp = inet6_sk(newsk);
940
941 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
942
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700943 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
944 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
945 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
946 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 /* Now IPv6 options...
949
950 First: no IPv4 options.
951 */
952 newinet->opt = NULL;
953
954 /* Clone RX bits */
955 newnp->rxopt.all = np->rxopt.all;
956
957 /* Clone pktoptions received with SYN */
958 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700959 if (treq->pktopts != NULL) {
960 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
961 kfree_skb(treq->pktopts);
962 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 if (newnp->pktoptions)
964 skb_set_owner_r(newnp->pktoptions, newsk);
965 }
966 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300967 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
969
970 /* Clone native IPv6 options from listening socket (if any)
971
972 Yes, keeping reference count would be much more clever,
973 but we make one more one thing there: reattach optmem
974 to newsk.
975 */
976 if (opt) {
977 newnp->opt = ipv6_dup_options(newsk, opt);
978 if (opt != np->opt)
979 sock_kfree_s(sk, opt, opt->tot_len);
980 }
981
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800982 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800984 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
985 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
John Heffner5d424d52006-03-20 17:53:41 -0800987 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 tcp_sync_mss(newsk, dst_mtu(dst));
989 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
990 tcp_initialize_rcv_mss(newsk);
991
992 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
993
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -0800994 __inet6_hash(&tcp_hashinfo, newsk);
Arnaldo Carvalho de Melo2d8c4ce2005-08-09 20:07:13 -0700995 inet_inherit_port(&tcp_hashinfo, sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
997 return newsk;
998
999out_overflow:
1000 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
1001out:
1002 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
1003 if (opt && opt != np->opt)
1004 sock_kfree_s(sk, opt, opt->tot_len);
1005 dst_release(dst);
1006 return NULL;
1007}
1008
1009static int tcp_v6_checksum_init(struct sk_buff *skb)
1010{
1011 if (skb->ip_summed == CHECKSUM_HW) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
Herbert Xufb286bb2005-11-10 13:01:24 -08001013 &skb->nh.ipv6h->daddr,skb->csum)) {
1014 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001018
1019 skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
1020 &skb->nh.ipv6h->daddr, 0);
1021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001023 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 }
1025 return 0;
1026}
1027
1028/* The socket must have it's spinlock held when we get
1029 * here.
1030 *
1031 * We have a potential double-lock case here, so even when
1032 * doing backlog processing we use the BH locking scheme.
1033 * This is because we cannot sleep with the original spinlock
1034 * held.
1035 */
1036static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1037{
1038 struct ipv6_pinfo *np = inet6_sk(sk);
1039 struct tcp_sock *tp;
1040 struct sk_buff *opt_skb = NULL;
1041
1042 /* Imagine: socket is IPv6. IPv4 packet arrives,
1043 goes to IPv4 receive handler and backlogged.
1044 From backlog it always goes here. Kerboom...
1045 Fortunately, tcp_rcv_established and rcv_established
1046 handle them correctly, but it is not case with
1047 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1048 */
1049
1050 if (skb->protocol == htons(ETH_P_IP))
1051 return tcp_v4_do_rcv(sk, skb);
1052
1053 if (sk_filter(sk, skb, 0))
1054 goto discard;
1055
1056 /*
1057 * socket locking is here for SMP purposes as backlog rcv
1058 * is currently called with bh processing disabled.
1059 */
1060
1061 /* Do Stevens' IPV6_PKTOPTIONS.
1062
1063 Yes, guys, it is the only place in our code, where we
1064 may make it not affecting IPv4.
1065 The rest of code is protocol independent,
1066 and I do not like idea to uglify IPv4.
1067
1068 Actually, all the idea behind IPV6_PKTOPTIONS
1069 looks not very well thought. For now we latch
1070 options, received in the last packet, enqueued
1071 by tcp. Feel free to propose better solution.
1072 --ANK (980728)
1073 */
1074 if (np->rxopt.all)
1075 opt_skb = skb_clone(skb, GFP_ATOMIC);
1076
1077 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1078 TCP_CHECK_TIMER(sk);
1079 if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
1080 goto reset;
1081 TCP_CHECK_TIMER(sk);
1082 if (opt_skb)
1083 goto ipv6_pktoptions;
1084 return 0;
1085 }
1086
1087 if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
1088 goto csum_err;
1089
1090 if (sk->sk_state == TCP_LISTEN) {
1091 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1092 if (!nsk)
1093 goto discard;
1094
1095 /*
1096 * Queue it on the new socket if the new socket is active,
1097 * otherwise we just shortcircuit this and continue with
1098 * the new socket..
1099 */
1100 if(nsk != sk) {
1101 if (tcp_child_process(sk, nsk, skb))
1102 goto reset;
1103 if (opt_skb)
1104 __kfree_skb(opt_skb);
1105 return 0;
1106 }
1107 }
1108
1109 TCP_CHECK_TIMER(sk);
1110 if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
1111 goto reset;
1112 TCP_CHECK_TIMER(sk);
1113 if (opt_skb)
1114 goto ipv6_pktoptions;
1115 return 0;
1116
1117reset:
1118 tcp_v6_send_reset(skb);
1119discard:
1120 if (opt_skb)
1121 __kfree_skb(opt_skb);
1122 kfree_skb(skb);
1123 return 0;
1124csum_err:
1125 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1126 goto discard;
1127
1128
1129ipv6_pktoptions:
1130 /* Do you ask, what is it?
1131
1132 1. skb was enqueued by tcp.
1133 2. skb is added to tail of read queue, rather than out of order.
1134 3. socket is not in passive state.
1135 4. Finally, it really contains options, which user wants to receive.
1136 */
1137 tp = tcp_sk(sk);
1138 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1139 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001140 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001141 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001142 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
1144 if (ipv6_opt_accepted(sk, opt_skb)) {
1145 skb_set_owner_r(opt_skb, sk);
1146 opt_skb = xchg(&np->pktoptions, opt_skb);
1147 } else {
1148 __kfree_skb(opt_skb);
1149 opt_skb = xchg(&np->pktoptions, NULL);
1150 }
1151 }
1152
1153 if (opt_skb)
1154 kfree_skb(opt_skb);
1155 return 0;
1156}
1157
Patrick McHardy951dbc82006-01-06 23:02:34 -08001158static int tcp_v6_rcv(struct sk_buff **pskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159{
1160 struct sk_buff *skb = *pskb;
1161 struct tcphdr *th;
1162 struct sock *sk;
1163 int ret;
1164
1165 if (skb->pkt_type != PACKET_HOST)
1166 goto discard_it;
1167
1168 /*
1169 * Count it even if it's bad.
1170 */
1171 TCP_INC_STATS_BH(TCP_MIB_INSEGS);
1172
1173 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1174 goto discard_it;
1175
1176 th = skb->h.th;
1177
1178 if (th->doff < sizeof(struct tcphdr)/4)
1179 goto bad_packet;
1180 if (!pskb_may_pull(skb, th->doff*4))
1181 goto discard_it;
1182
1183 if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
Herbert Xufb286bb2005-11-10 13:01:24 -08001184 tcp_v6_checksum_init(skb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 goto bad_packet;
1186
1187 th = skb->h.th;
1188 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1189 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1190 skb->len - th->doff*4);
1191 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1192 TCP_SKB_CB(skb)->when = 0;
1193 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
1194 TCP_SKB_CB(skb)->sacked = 0;
1195
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001196 sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source,
1197 &skb->nh.ipv6h->daddr, ntohs(th->dest),
1198 inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200 if (!sk)
1201 goto no_tcp_socket;
1202
1203process:
1204 if (sk->sk_state == TCP_TIME_WAIT)
1205 goto do_time_wait;
1206
1207 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1208 goto discard_and_relse;
1209
1210 if (sk_filter(sk, skb, 0))
1211 goto discard_and_relse;
1212
1213 skb->dev = NULL;
1214
1215 bh_lock_sock(sk);
1216 ret = 0;
1217 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001218#ifdef CONFIG_NET_DMA
1219 struct tcp_sock *tp = tcp_sk(sk);
1220 if (tp->ucopy.dma_chan)
1221 ret = tcp_v6_do_rcv(sk, skb);
1222 else
1223#endif
1224 {
1225 if (!tcp_prequeue(sk, skb))
1226 ret = tcp_v6_do_rcv(sk, skb);
1227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 } else
1229 sk_add_backlog(sk, skb);
1230 bh_unlock_sock(sk);
1231
1232 sock_put(sk);
1233 return ret ? -1 : 0;
1234
1235no_tcp_socket:
1236 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1237 goto discard_it;
1238
1239 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1240bad_packet:
1241 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1242 } else {
1243 tcp_v6_send_reset(skb);
1244 }
1245
1246discard_it:
1247
1248 /*
1249 * Discard frame
1250 */
1251
1252 kfree_skb(skb);
1253 return 0;
1254
1255discard_and_relse:
1256 sock_put(sk);
1257 goto discard_it;
1258
1259do_time_wait:
1260 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001261 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 goto discard_it;
1263 }
1264
1265 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1266 TCP_INC_STATS_BH(TCP_MIB_INERRS);
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001267 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 goto discard_it;
1269 }
1270
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001271 switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
1272 skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 case TCP_TW_SYN:
1274 {
1275 struct sock *sk2;
1276
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001277 sk2 = inet6_lookup_listener(&tcp_hashinfo,
1278 &skb->nh.ipv6h->daddr,
1279 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001281 struct inet_timewait_sock *tw = inet_twsk(sk);
1282 inet_twsk_deschedule(tw, &tcp_death_row);
1283 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 sk = sk2;
1285 goto process;
1286 }
1287 /* Fall through to ACK */
1288 }
1289 case TCP_TW_ACK:
1290 tcp_v6_timewait_ack(sk, skb);
1291 break;
1292 case TCP_TW_RST:
1293 goto no_tcp_socket;
1294 case TCP_TW_SUCCESS:;
1295 }
1296 goto discard_it;
1297}
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299static int tcp_v6_remember_stamp(struct sock *sk)
1300{
1301 /* Alas, not yet... */
1302 return 0;
1303}
1304
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001305static struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001306 .queue_xmit = inet6_csk_xmit,
1307 .send_check = tcp_v6_send_check,
1308 .rebuild_header = inet6_sk_rebuild_header,
1309 .conn_request = tcp_v6_conn_request,
1310 .syn_recv_sock = tcp_v6_syn_recv_sock,
1311 .remember_stamp = tcp_v6_remember_stamp,
1312 .net_header_len = sizeof(struct ipv6hdr),
1313 .setsockopt = ipv6_setsockopt,
1314 .getsockopt = ipv6_getsockopt,
1315 .addr2sockaddr = inet6_csk_addr2sockaddr,
1316 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001317#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001318 .compat_setsockopt = compat_ipv6_setsockopt,
1319 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001320#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321};
1322
1323/*
1324 * TCP over IPv4 via INET6 API
1325 */
1326
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001327static struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001328 .queue_xmit = ip_queue_xmit,
1329 .send_check = tcp_v4_send_check,
1330 .rebuild_header = inet_sk_rebuild_header,
1331 .conn_request = tcp_v6_conn_request,
1332 .syn_recv_sock = tcp_v6_syn_recv_sock,
1333 .remember_stamp = tcp_v4_remember_stamp,
1334 .net_header_len = sizeof(struct iphdr),
1335 .setsockopt = ipv6_setsockopt,
1336 .getsockopt = ipv6_getsockopt,
1337 .addr2sockaddr = inet6_csk_addr2sockaddr,
1338 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001339#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001340 .compat_setsockopt = compat_ipv6_setsockopt,
1341 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001342#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343};
1344
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345/* NOTE: A lot of things set to zero explicitly by call to
1346 * sk_alloc() so need not be done here.
1347 */
1348static int tcp_v6_init_sock(struct sock *sk)
1349{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001350 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 struct tcp_sock *tp = tcp_sk(sk);
1352
1353 skb_queue_head_init(&tp->out_of_order_queue);
1354 tcp_init_xmit_timers(sk);
1355 tcp_prequeue_init(tp);
1356
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001357 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 tp->mdev = TCP_TIMEOUT_INIT;
1359
1360 /* So many TCP implementations out there (incorrectly) count the
1361 * initial SYN frame in their delayed-ACK and congestion control
1362 * algorithms that we must have the following bandaid to talk
1363 * efficiently to them. -DaveM
1364 */
1365 tp->snd_cwnd = 2;
1366
1367 /* See draft-stevens-tcpca-spec-01 for discussion of the
1368 * initialization of these values.
1369 */
1370 tp->snd_ssthresh = 0x7fffffff;
1371 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001372 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 tp->reordering = sysctl_tcp_reordering;
1375
1376 sk->sk_state = TCP_CLOSE;
1377
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001378 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001379 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001380 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 sk->sk_write_space = sk_stream_write_space;
1382 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1383
1384 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1385 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1386
1387 atomic_inc(&tcp_sockets_allocated);
1388
1389 return 0;
1390}
1391
1392static int tcp_v6_destroy_sock(struct sock *sk)
1393{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 tcp_v4_destroy_sock(sk);
1395 return inet6_destroy_sock(sk);
1396}
1397
1398/* Proc filesystem TCPv6 sock list dumping. */
1399static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001400 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001403 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1404 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
1406 if (ttd < 0)
1407 ttd = 0;
1408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 seq_printf(seq,
1410 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1411 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1412 i,
1413 src->s6_addr32[0], src->s6_addr32[1],
1414 src->s6_addr32[2], src->s6_addr32[3],
1415 ntohs(inet_sk(sk)->sport),
1416 dest->s6_addr32[0], dest->s6_addr32[1],
1417 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001418 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 TCP_SYN_RECV,
1420 0,0, /* could print option size, but that is af dependent. */
1421 1, /* timers active (only the expire timer) */
1422 jiffies_to_clock_t(ttd),
1423 req->retrans,
1424 uid,
1425 0, /* non standard timer */
1426 0, /* open_requests have no inode */
1427 0, req);
1428}
1429
1430static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1431{
1432 struct in6_addr *dest, *src;
1433 __u16 destp, srcp;
1434 int timer_active;
1435 unsigned long timer_expires;
1436 struct inet_sock *inet = inet_sk(sp);
1437 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001438 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 struct ipv6_pinfo *np = inet6_sk(sp);
1440
1441 dest = &np->daddr;
1442 src = &np->rcv_saddr;
1443 destp = ntohs(inet->dport);
1444 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001445
1446 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001448 timer_expires = icsk->icsk_timeout;
1449 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001451 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 } else if (timer_pending(&sp->sk_timer)) {
1453 timer_active = 2;
1454 timer_expires = sp->sk_timer.expires;
1455 } else {
1456 timer_active = 0;
1457 timer_expires = jiffies;
1458 }
1459
1460 seq_printf(seq,
1461 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1462 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
1463 i,
1464 src->s6_addr32[0], src->s6_addr32[1],
1465 src->s6_addr32[2], src->s6_addr32[3], srcp,
1466 dest->s6_addr32[0], dest->s6_addr32[1],
1467 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1468 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07001469 tp->write_seq-tp->snd_una,
1470 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 timer_active,
1472 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001473 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001475 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 sock_i_ino(sp),
1477 atomic_read(&sp->sk_refcnt), sp,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001478 icsk->icsk_rto,
1479 icsk->icsk_ack.ato,
1480 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
1482 );
1483}
1484
1485static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001486 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
1488 struct in6_addr *dest, *src;
1489 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001490 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 int ttd = tw->tw_ttd - jiffies;
1492
1493 if (ttd < 0)
1494 ttd = 0;
1495
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001496 dest = &tw6->tw_v6_daddr;
1497 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 destp = ntohs(tw->tw_dport);
1499 srcp = ntohs(tw->tw_sport);
1500
1501 seq_printf(seq,
1502 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1503 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1504 i,
1505 src->s6_addr32[0], src->s6_addr32[1],
1506 src->s6_addr32[2], src->s6_addr32[3], srcp,
1507 dest->s6_addr32[0], dest->s6_addr32[1],
1508 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1509 tw->tw_substate, 0, 0,
1510 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1511 atomic_read(&tw->tw_refcnt), tw);
1512}
1513
1514#ifdef CONFIG_PROC_FS
1515static int tcp6_seq_show(struct seq_file *seq, void *v)
1516{
1517 struct tcp_iter_state *st;
1518
1519 if (v == SEQ_START_TOKEN) {
1520 seq_puts(seq,
1521 " sl "
1522 "local_address "
1523 "remote_address "
1524 "st tx_queue rx_queue tr tm->when retrnsmt"
1525 " uid timeout inode\n");
1526 goto out;
1527 }
1528 st = seq->private;
1529
1530 switch (st->state) {
1531 case TCP_SEQ_STATE_LISTENING:
1532 case TCP_SEQ_STATE_ESTABLISHED:
1533 get_tcp6_sock(seq, v, st->num);
1534 break;
1535 case TCP_SEQ_STATE_OPENREQ:
1536 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
1537 break;
1538 case TCP_SEQ_STATE_TIME_WAIT:
1539 get_timewait6_sock(seq, v, st->num);
1540 break;
1541 }
1542out:
1543 return 0;
1544}
1545
1546static struct file_operations tcp6_seq_fops;
1547static struct tcp_seq_afinfo tcp6_seq_afinfo = {
1548 .owner = THIS_MODULE,
1549 .name = "tcp6",
1550 .family = AF_INET6,
1551 .seq_show = tcp6_seq_show,
1552 .seq_fops = &tcp6_seq_fops,
1553};
1554
1555int __init tcp6_proc_init(void)
1556{
1557 return tcp_proc_register(&tcp6_seq_afinfo);
1558}
1559
1560void tcp6_proc_exit(void)
1561{
1562 tcp_proc_unregister(&tcp6_seq_afinfo);
1563}
1564#endif
1565
1566struct proto tcpv6_prot = {
1567 .name = "TCPv6",
1568 .owner = THIS_MODULE,
1569 .close = tcp_close,
1570 .connect = tcp_v6_connect,
1571 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001572 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 .ioctl = tcp_ioctl,
1574 .init = tcp_v6_init_sock,
1575 .destroy = tcp_v6_destroy_sock,
1576 .shutdown = tcp_shutdown,
1577 .setsockopt = tcp_setsockopt,
1578 .getsockopt = tcp_getsockopt,
1579 .sendmsg = tcp_sendmsg,
1580 .recvmsg = tcp_recvmsg,
1581 .backlog_rcv = tcp_v6_do_rcv,
1582 .hash = tcp_v6_hash,
1583 .unhash = tcp_unhash,
1584 .get_port = tcp_v6_get_port,
1585 .enter_memory_pressure = tcp_enter_memory_pressure,
1586 .sockets_allocated = &tcp_sockets_allocated,
1587 .memory_allocated = &tcp_memory_allocated,
1588 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07001589 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 .sysctl_mem = sysctl_tcp_mem,
1591 .sysctl_wmem = sysctl_tcp_wmem,
1592 .sysctl_rmem = sysctl_tcp_rmem,
1593 .max_header = MAX_TCP_HEADER,
1594 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08001595 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001596 .rsk_prot = &tcp6_request_sock_ops,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001597#ifdef CONFIG_COMPAT
1598 .compat_setsockopt = compat_tcp_setsockopt,
1599 .compat_getsockopt = compat_tcp_getsockopt,
1600#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601};
1602
1603static struct inet6_protocol tcpv6_protocol = {
1604 .handler = tcp_v6_rcv,
1605 .err_handler = tcp_v6_err,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07001606 .gso_segment = tcp_tso_segment,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1608};
1609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610static struct inet_protosw tcpv6_protosw = {
1611 .type = SOCK_STREAM,
1612 .protocol = IPPROTO_TCP,
1613 .prot = &tcpv6_prot,
1614 .ops = &inet6_stream_ops,
1615 .capability = -1,
1616 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001617 .flags = INET_PROTOSW_PERMANENT |
1618 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619};
1620
1621void __init tcpv6_init(void)
1622{
1623 /* register inet6 protocol */
1624 if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
1625 printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
1626 inet6_register_protosw(&tcpv6_protosw);
David Woodhouseae0f7d52006-01-11 15:53:04 -08001627
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08001628 if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW,
1629 IPPROTO_TCP) < 0)
David Woodhouseae0f7d52006-01-11 15:53:04 -08001630 panic("Failed to create the TCPv6 control socket.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631}