blob: a682eb9093e13b3bc2c25c35c649418b52032a4c [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>
29#include <linux/config.h>
30#include <linux/errno.h>
31#include <linux/types.h>
32#include <linux/socket.h>
33#include <linux/sockios.h>
34#include <linux/net.h>
35#include <linux/jiffies.h>
36#include <linux/in.h>
37#include <linux/in6.h>
38#include <linux/netdevice.h>
39#include <linux/init.h>
40#include <linux/jhash.h>
41#include <linux/ipsec.h>
42#include <linux/times.h>
43
44#include <linux/ipv6.h>
45#include <linux/icmpv6.h>
46#include <linux/random.h>
47
48#include <net/tcp.h>
49#include <net/ndisc.h>
Arnaldo Carvalho de Melo5324a042005-08-12 09:26:18 -030050#include <net/inet6_hashtables.h>
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -080051#include <net/inet6_connection_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <net/ipv6.h>
53#include <net/transp_v6.h>
54#include <net/addrconf.h>
55#include <net/ip6_route.h>
56#include <net/ip6_checksum.h>
57#include <net/inet_ecn.h>
58#include <net/protocol.h>
59#include <net/xfrm.h>
60#include <net/addrconf.h>
61#include <net/snmp.h>
62#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080063#include <net/timewait_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include <asm/uaccess.h>
66
67#include <linux/proc_fs.h>
68#include <linux/seq_file.h>
69
70static void tcp_v6_send_reset(struct sk_buff *skb);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -070071static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080072static void tcp_v6_send_check(struct sock *sk, int len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 struct sk_buff *skb);
74
75static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080077static struct inet_connection_sock_af_ops ipv6_mapped;
78static struct inet_connection_sock_af_ops ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
81{
Arnaldo Carvalho de Melo971af182005-12-13 23:14:47 -080082 return inet_csk_get_port(&tcp_hashinfo, sk, snum,
83 inet6_csk_bind_conflict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084}
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086static void tcp_v6_hash(struct sock *sk)
87{
88 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080089 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 tcp_prot.hash(sk);
91 return;
92 }
93 local_bh_disable();
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -080094 __inet6_hash(&tcp_hashinfo, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 local_bh_enable();
96 }
97}
98
Linus Torvalds1da177e2005-04-16 15:20:36 -070099static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
100 struct in6_addr *saddr,
101 struct in6_addr *daddr,
102 unsigned long base)
103{
104 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
105}
106
107static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
108{
109 if (skb->protocol == htons(ETH_P_IPV6)) {
110 return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
111 skb->nh.ipv6h->saddr.s6_addr32,
112 skb->h.th->dest,
113 skb->h.th->source);
114 } else {
115 return secure_tcp_sequence_number(skb->nh.iph->daddr,
116 skb->nh.iph->saddr,
117 skb->h.th->dest,
118 skb->h.th->source);
119 }
120}
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
123 int addr_len)
124{
125 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
126 struct inet_sock *inet = inet_sk(sk);
127 struct ipv6_pinfo *np = inet6_sk(sk);
128 struct tcp_sock *tp = tcp_sk(sk);
129 struct in6_addr *saddr = NULL, *final_p = NULL, final;
130 struct flowi fl;
131 struct dst_entry *dst;
132 int addr_type;
133 int err;
134
135 if (addr_len < SIN6_LEN_RFC2133)
136 return -EINVAL;
137
138 if (usin->sin6_family != AF_INET6)
139 return(-EAFNOSUPPORT);
140
141 memset(&fl, 0, sizeof(fl));
142
143 if (np->sndflow) {
144 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
145 IP6_ECN_flow_init(fl.fl6_flowlabel);
146 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
147 struct ip6_flowlabel *flowlabel;
148 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
149 if (flowlabel == NULL)
150 return -EINVAL;
151 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
152 fl6_sock_release(flowlabel);
153 }
154 }
155
156 /*
157 * connect() to INADDR_ANY means loopback (BSD'ism).
158 */
159
160 if(ipv6_addr_any(&usin->sin6_addr))
161 usin->sin6_addr.s6_addr[15] = 0x1;
162
163 addr_type = ipv6_addr_type(&usin->sin6_addr);
164
165 if(addr_type & IPV6_ADDR_MULTICAST)
166 return -ENETUNREACH;
167
168 if (addr_type&IPV6_ADDR_LINKLOCAL) {
169 if (addr_len >= sizeof(struct sockaddr_in6) &&
170 usin->sin6_scope_id) {
171 /* If interface is set while binding, indices
172 * must coincide.
173 */
174 if (sk->sk_bound_dev_if &&
175 sk->sk_bound_dev_if != usin->sin6_scope_id)
176 return -EINVAL;
177
178 sk->sk_bound_dev_if = usin->sin6_scope_id;
179 }
180
181 /* Connect to link-local address requires an interface */
182 if (!sk->sk_bound_dev_if)
183 return -EINVAL;
184 }
185
186 if (tp->rx_opt.ts_recent_stamp &&
187 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
188 tp->rx_opt.ts_recent = 0;
189 tp->rx_opt.ts_recent_stamp = 0;
190 tp->write_seq = 0;
191 }
192
193 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
194 np->flow_label = fl.fl6_flowlabel;
195
196 /*
197 * TCP over IPv4
198 */
199
200 if (addr_type == IPV6_ADDR_MAPPED) {
201 u32 exthdrlen = tp->ext_header_len;
202 struct sockaddr_in sin;
203
204 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
205
206 if (__ipv6_only_sock(sk))
207 return -ENETUNREACH;
208
209 sin.sin_family = AF_INET;
210 sin.sin_port = usin->sin6_port;
211 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
212
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800213 inet_csk(sk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 sk->sk_backlog_rcv = tcp_v4_do_rcv;
215
216 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
217
218 if (err) {
219 tp->ext_header_len = exthdrlen;
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800220 inet_csk(sk)->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 sk->sk_backlog_rcv = tcp_v6_do_rcv;
222 goto failure;
223 } else {
224 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
225 inet->saddr);
226 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
227 inet->rcv_saddr);
228 }
229
230 return err;
231 }
232
233 if (!ipv6_addr_any(&np->rcv_saddr))
234 saddr = &np->rcv_saddr;
235
236 fl.proto = IPPROTO_TCP;
237 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
238 ipv6_addr_copy(&fl.fl6_src,
239 (saddr ? saddr : &np->saddr));
240 fl.oif = sk->sk_bound_dev_if;
241 fl.fl_ip_dport = usin->sin6_port;
242 fl.fl_ip_sport = inet->sport;
243
244 if (np->opt && np->opt->srcrt) {
245 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
246 ipv6_addr_copy(&final, &fl.fl6_dst);
247 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
248 final_p = &final;
249 }
250
251 err = ip6_dst_lookup(sk, &dst, &fl);
252 if (err)
253 goto failure;
254 if (final_p)
255 ipv6_addr_copy(&fl.fl6_dst, final_p);
256
Patrick McHardye1044112005-09-08 15:11:55 -0700257 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 if (saddr == NULL) {
261 saddr = &fl.fl6_src;
262 ipv6_addr_copy(&np->rcv_saddr, saddr);
263 }
264
265 /* set the source address */
266 ipv6_addr_copy(&np->saddr, saddr);
267 inet->rcv_saddr = LOOPBACK4_IPV6;
268
269 ip6_dst_store(sk, dst, NULL);
270 sk->sk_route_caps = dst->dev->features &
271 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
272
273 tp->ext_header_len = 0;
274 if (np->opt)
275 tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
276
277 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
278
279 inet->dport = usin->sin6_port;
280
281 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800282 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if (err)
284 goto late_failure;
285
286 if (!tp->write_seq)
287 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
288 np->daddr.s6_addr32,
289 inet->sport,
290 inet->dport);
291
292 err = tcp_connect(sk);
293 if (err)
294 goto late_failure;
295
296 return 0;
297
298late_failure:
299 tcp_set_state(sk, TCP_CLOSE);
300 __sk_dst_reset(sk);
301failure:
302 inet->dport = 0;
303 sk->sk_route_caps = 0;
304 return err;
305}
306
307static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
308 int type, int code, int offset, __u32 info)
309{
310 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300311 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 struct ipv6_pinfo *np;
313 struct sock *sk;
314 int err;
315 struct tcp_sock *tp;
316 __u32 seq;
317
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300318 sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
319 th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 if (sk == NULL) {
322 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
323 return;
324 }
325
326 if (sk->sk_state == TCP_TIME_WAIT) {
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700327 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 return;
329 }
330
331 bh_lock_sock(sk);
332 if (sock_owned_by_user(sk))
333 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
334
335 if (sk->sk_state == TCP_CLOSE)
336 goto out;
337
338 tp = tcp_sk(sk);
339 seq = ntohl(th->seq);
340 if (sk->sk_state != TCP_LISTEN &&
341 !between(seq, tp->snd_una, tp->snd_nxt)) {
342 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
343 goto out;
344 }
345
346 np = inet6_sk(sk);
347
348 if (type == ICMPV6_PKT_TOOBIG) {
349 struct dst_entry *dst = NULL;
350
351 if (sock_owned_by_user(sk))
352 goto out;
353 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
354 goto out;
355
356 /* icmp should have updated the destination cache entry */
357 dst = __sk_dst_check(sk, np->dst_cookie);
358
359 if (dst == NULL) {
360 struct inet_sock *inet = inet_sk(sk);
361 struct flowi fl;
362
363 /* BUGGG_FUTURE: Again, it is not clear how
364 to handle rthdr case. Ignore this complexity
365 for now.
366 */
367 memset(&fl, 0, sizeof(fl));
368 fl.proto = IPPROTO_TCP;
369 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
370 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
371 fl.oif = sk->sk_bound_dev_if;
372 fl.fl_ip_dport = inet->dport;
373 fl.fl_ip_sport = inet->sport;
374
375 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
376 sk->sk_err_soft = -err;
377 goto out;
378 }
379
380 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
381 sk->sk_err_soft = -err;
382 goto out;
383 }
384
385 } else
386 dst_hold(dst);
387
388 if (tp->pmtu_cookie > dst_mtu(dst)) {
389 tcp_sync_mss(sk, dst_mtu(dst));
390 tcp_simple_retransmit(sk);
391 } /* else let the usual retransmit timer handle it */
392 dst_release(dst);
393 goto out;
394 }
395
396 icmpv6_err_convert(type, code, &err);
397
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700398 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700400 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 case TCP_LISTEN:
402 if (sock_owned_by_user(sk))
403 goto out;
404
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800405 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
406 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 if (!req)
408 goto out;
409
410 /* ICMPs are not backlogged, hence we cannot get
411 * an established socket here.
412 */
413 BUG_TRAP(req->sk == NULL);
414
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700415 if (seq != tcp_rsk(req)->snt_isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
417 goto out;
418 }
419
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700420 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 goto out;
422
423 case TCP_SYN_SENT:
424 case TCP_SYN_RECV: /* Cannot happen.
425 It can, it SYNs are crossed. --ANK */
426 if (!sock_owned_by_user(sk)) {
427 TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
428 sk->sk_err = err;
429 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
430
431 tcp_done(sk);
432 } else
433 sk->sk_err_soft = err;
434 goto out;
435 }
436
437 if (!sock_owned_by_user(sk) && np->recverr) {
438 sk->sk_err = err;
439 sk->sk_error_report(sk);
440 } else
441 sk->sk_err_soft = err;
442
443out:
444 bh_unlock_sock(sk);
445 sock_put(sk);
446}
447
448
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700449static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 struct dst_entry *dst)
451{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800452 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 struct ipv6_pinfo *np = inet6_sk(sk);
454 struct sk_buff * skb;
455 struct ipv6_txoptions *opt = NULL;
456 struct in6_addr * final_p = NULL, final;
457 struct flowi fl;
458 int err = -1;
459
460 memset(&fl, 0, sizeof(fl));
461 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700462 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
463 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700465 fl.oif = treq->iif;
466 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 fl.fl_ip_sport = inet_sk(sk)->sport;
468
469 if (dst == NULL) {
470 opt = np->opt;
471 if (opt == NULL &&
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900472 np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700473 treq->pktopts) {
474 struct sk_buff *pktopts = treq->pktopts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 struct inet6_skb_parm *rxopt = IP6CB(pktopts);
476 if (rxopt->srcrt)
477 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt));
478 }
479
480 if (opt && opt->srcrt) {
481 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
482 ipv6_addr_copy(&final, &fl.fl6_dst);
483 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
484 final_p = &final;
485 }
486
487 err = ip6_dst_lookup(sk, &dst, &fl);
488 if (err)
489 goto done;
490 if (final_p)
491 ipv6_addr_copy(&fl.fl6_dst, final_p);
492 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
493 goto done;
494 }
495
496 skb = tcp_make_synack(sk, dst, req);
497 if (skb) {
498 struct tcphdr *th = skb->h.th;
499
500 th->check = tcp_v6_check(th, skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700501 &treq->loc_addr, &treq->rmt_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 csum_partial((char *)th, skb->len, skb->csum));
503
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700504 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 err = ip6_xmit(sk, skb, &fl, opt, 0);
506 if (err == NET_XMIT_CN)
507 err = 0;
508 }
509
510done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 if (opt && opt != np->opt)
512 sock_kfree_s(sk, opt, opt->tot_len);
513 return err;
514}
515
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700516static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800518 if (inet6_rsk(req)->pktopts)
519 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
521
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700522static struct request_sock_ops tcp6_request_sock_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700524 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700526 .send_ack = tcp_v6_reqsk_send_ack,
527 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 .send_reset = tcp_v6_send_reset
529};
530
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800531static struct timewait_sock_ops tcp6_timewait_sock_ops = {
532 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
533 .twsk_unique = tcp_twsk_unique,
534};
535
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800536static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
538 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800539 struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 if (skb->ip_summed == CHECKSUM_HW) {
542 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
543 skb->csum = offsetof(struct tcphdr, check);
544 } else {
545 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
546 csum_partial((char *)th, th->doff<<2,
547 skb->csum));
548 }
549}
550
551
552static void tcp_v6_send_reset(struct sk_buff *skb)
553{
554 struct tcphdr *th = skb->h.th, *t1;
555 struct sk_buff *buff;
556 struct flowi fl;
557
558 if (th->rst)
559 return;
560
561 if (!ipv6_unicast_destination(skb))
562 return;
563
564 /*
565 * We need to grab some memory, and put together an RST,
566 * and then put it into the queue to be sent.
567 */
568
569 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr),
570 GFP_ATOMIC);
571 if (buff == NULL)
572 return;
573
574 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
575
576 t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
577
578 /* Swap the send and the receive. */
579 memset(t1, 0, sizeof(*t1));
580 t1->dest = th->source;
581 t1->source = th->dest;
582 t1->doff = sizeof(*t1)/4;
583 t1->rst = 1;
584
585 if(th->ack) {
586 t1->seq = th->ack_seq;
587 } else {
588 t1->ack = 1;
589 t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
590 + skb->len - (th->doff<<2));
591 }
592
593 buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
594
595 memset(&fl, 0, sizeof(fl));
596 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
597 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
598
599 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
600 sizeof(*t1), IPPROTO_TCP,
601 buff->csum);
602
603 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300604 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 fl.fl_ip_dport = t1->dest;
606 fl.fl_ip_sport = t1->source;
607
608 /* sk = NULL, but it is safe for now. RST socket required. */
609 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
610
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800611 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
612 ip6_xmit(NULL, buff, &fl, NULL, 0);
613 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
614 TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
619 kfree_skb(buff);
620}
621
622static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
623{
624 struct tcphdr *th = skb->h.th, *t1;
625 struct sk_buff *buff;
626 struct flowi fl;
627 int tot_len = sizeof(struct tcphdr);
628
629 if (ts)
630 tot_len += 3*4;
631
632 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
633 GFP_ATOMIC);
634 if (buff == NULL)
635 return;
636
637 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
638
639 t1 = (struct tcphdr *) skb_push(buff,tot_len);
640
641 /* Swap the send and the receive. */
642 memset(t1, 0, sizeof(*t1));
643 t1->dest = th->source;
644 t1->source = th->dest;
645 t1->doff = tot_len/4;
646 t1->seq = htonl(seq);
647 t1->ack_seq = htonl(ack);
648 t1->ack = 1;
649 t1->window = htons(win);
650
651 if (ts) {
652 u32 *ptr = (u32*)(t1 + 1);
653 *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
654 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
655 *ptr++ = htonl(tcp_time_stamp);
656 *ptr = htonl(ts);
657 }
658
659 buff->csum = csum_partial((char *)t1, tot_len, 0);
660
661 memset(&fl, 0, sizeof(fl));
662 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
663 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
664
665 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
666 tot_len, IPPROTO_TCP,
667 buff->csum);
668
669 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300670 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 fl.fl_ip_dport = t1->dest;
672 fl.fl_ip_sport = t1->source;
673
674 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800675 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
676 ip6_xmit(NULL, buff, &fl, NULL, 0);
677 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681
682 kfree_skb(buff);
683}
684
685static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
686{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700687 struct inet_timewait_sock *tw = inet_twsk(sk);
688 const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700690 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
691 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
692 tcptw->tw_ts_recent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700694 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700697static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700699 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 -0700700}
701
702
703static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
704{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700705 struct request_sock *req, **prev;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300706 const struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 struct sock *nsk;
708
709 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800710 req = inet6_csk_search_req(sk, &prev, th->source,
711 &skb->nh.ipv6h->saddr,
712 &skb->nh.ipv6h->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (req)
714 return tcp_check_req(sk, skb, req, prev);
715
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300716 nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr,
717 th->source, &skb->nh.ipv6h->daddr,
718 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 if (nsk) {
721 if (nsk->sk_state != TCP_TIME_WAIT) {
722 bh_lock_sock(nsk);
723 return nsk;
724 }
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -0700725 inet_twsk_put((struct inet_timewait_sock *)nsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return NULL;
727 }
728
729#if 0 /*def CONFIG_SYN_COOKIES*/
730 if (!th->rst && !th->syn && th->ack)
731 sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
732#endif
733 return sk;
734}
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736/* FIXME: this is substantially similar to the ipv4 code.
737 * Can some kind of merge be done? -- erics
738 */
739static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
740{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800741 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 struct ipv6_pinfo *np = inet6_sk(sk);
743 struct tcp_options_received tmp_opt;
744 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700745 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 __u32 isn = TCP_SKB_CB(skb)->when;
747
748 if (skb->protocol == htons(ETH_P_IP))
749 return tcp_v4_conn_request(sk, skb);
750
751 if (!ipv6_unicast_destination(skb))
752 goto drop;
753
754 /*
755 * There are no SYN attacks on IPv6, yet...
756 */
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700757 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (net_ratelimit())
759 printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
760 goto drop;
761 }
762
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700763 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 goto drop;
765
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800766 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (req == NULL)
768 goto drop;
769
770 tcp_clear_options(&tmp_opt);
771 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
772 tmp_opt.user_mss = tp->rx_opt.user_mss;
773
774 tcp_parse_options(skb, &tmp_opt, 0);
775
776 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
777 tcp_openreq_init(req, &tmp_opt, skb);
778
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800779 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700780 ipv6_addr_copy(&treq->rmt_addr, &skb->nh.ipv6h->saddr);
781 ipv6_addr_copy(&treq->loc_addr, &skb->nh.ipv6h->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 TCP_ECN_create_request(req, skb->h.th);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700783 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (ipv6_opt_accepted(sk, skb) ||
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900785 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
786 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 atomic_inc(&skb->users);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700788 treq->pktopts = skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700790 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 /* So that link locals have meaning */
793 if (!sk->sk_bound_dev_if &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700794 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300795 treq->iif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 if (isn == 0)
798 isn = tcp_v6_init_sequence(sk,skb);
799
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700800 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 if (tcp_v6_send_synack(sk, req, NULL))
803 goto drop;
804
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800805 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return 0;
807
808drop:
809 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700810 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
813 return 0; /* don't send reset */
814}
815
816static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700817 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 struct dst_entry *dst)
819{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800820 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
822 struct tcp6_sock *newtcp6sk;
823 struct inet_sock *newinet;
824 struct tcp_sock *newtp;
825 struct sock *newsk;
826 struct ipv6_txoptions *opt;
827
828 if (skb->protocol == htons(ETH_P_IP)) {
829 /*
830 * v6 mapped
831 */
832
833 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
834
835 if (newsk == NULL)
836 return NULL;
837
838 newtcp6sk = (struct tcp6_sock *)newsk;
839 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
840
841 newinet = inet_sk(newsk);
842 newnp = inet6_sk(newsk);
843 newtp = tcp_sk(newsk);
844
845 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
846
847 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
848 newinet->daddr);
849
850 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
851 newinet->saddr);
852
853 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
854
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800855 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
857 newnp->pktoptions = NULL;
858 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300859 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
861
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -0700862 /*
863 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
864 * here, tcp_create_openreq_child now does this for us, see the comment in
865 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800869 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 Sync it now.
871 */
872 tcp_sync_mss(newsk, newtp->pmtu_cookie);
873
874 return newsk;
875 }
876
877 opt = np->opt;
878
879 if (sk_acceptq_is_full(sk))
880 goto out_overflow;
881
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900882 if (np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700883 opt == NULL && treq->pktopts) {
884 struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 if (rxopt->srcrt)
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700886 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr *)(treq->pktopts->nh.raw + rxopt->srcrt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 }
888
889 if (dst == NULL) {
890 struct in6_addr *final_p = NULL, final;
891 struct flowi fl;
892
893 memset(&fl, 0, sizeof(fl));
894 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700895 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if (opt && opt->srcrt) {
897 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
898 ipv6_addr_copy(&final, &fl.fl6_dst);
899 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
900 final_p = &final;
901 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700902 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700904 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 fl.fl_ip_sport = inet_sk(sk)->sport;
906
907 if (ip6_dst_lookup(sk, &dst, &fl))
908 goto out;
909
910 if (final_p)
911 ipv6_addr_copy(&fl.fl6_dst, final_p);
912
913 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
914 goto out;
915 }
916
917 newsk = tcp_create_openreq_child(sk, req, skb);
918 if (newsk == NULL)
919 goto out;
920
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -0700921 /*
922 * No need to charge this sock to the relevant IPv6 refcnt debug socks
923 * count here, tcp_create_openreq_child now does this for us, see the
924 * comment in that function for the gory details. -acme
925 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 ip6_dst_store(newsk, dst, NULL);
928 newsk->sk_route_caps = dst->dev->features &
929 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
930
931 newtcp6sk = (struct tcp6_sock *)newsk;
932 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
933
934 newtp = tcp_sk(newsk);
935 newinet = inet_sk(newsk);
936 newnp = inet6_sk(newsk);
937
938 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
939
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700940 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
941 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
942 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
943 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 /* Now IPv6 options...
946
947 First: no IPv4 options.
948 */
949 newinet->opt = NULL;
950
951 /* Clone RX bits */
952 newnp->rxopt.all = np->rxopt.all;
953
954 /* Clone pktoptions received with SYN */
955 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700956 if (treq->pktopts != NULL) {
957 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
958 kfree_skb(treq->pktopts);
959 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 if (newnp->pktoptions)
961 skb_set_owner_r(newnp->pktoptions, newsk);
962 }
963 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300964 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
966
967 /* Clone native IPv6 options from listening socket (if any)
968
969 Yes, keeping reference count would be much more clever,
970 but we make one more one thing there: reattach optmem
971 to newsk.
972 */
973 if (opt) {
974 newnp->opt = ipv6_dup_options(newsk, opt);
975 if (opt != np->opt)
976 sock_kfree_s(sk, opt, opt->tot_len);
977 }
978
979 newtp->ext_header_len = 0;
980 if (newnp->opt)
981 newtp->ext_header_len = newnp->opt->opt_nflen +
982 newnp->opt->opt_flen;
983
984 tcp_sync_mss(newsk, dst_mtu(dst));
985 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
986 tcp_initialize_rcv_mss(newsk);
987
988 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
989
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -0800990 __inet6_hash(&tcp_hashinfo, newsk);
Arnaldo Carvalho de Melo2d8c4ce2005-08-09 20:07:13 -0700991 inet_inherit_port(&tcp_hashinfo, sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 return newsk;
994
995out_overflow:
996 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
997out:
998 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
999 if (opt && opt != np->opt)
1000 sock_kfree_s(sk, opt, opt->tot_len);
1001 dst_release(dst);
1002 return NULL;
1003}
1004
1005static int tcp_v6_checksum_init(struct sk_buff *skb)
1006{
1007 if (skb->ip_summed == CHECKSUM_HW) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
Herbert Xufb286bb2005-11-10 13:01:24 -08001009 &skb->nh.ipv6h->daddr,skb->csum)) {
1010 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001014
1015 skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
1016 &skb->nh.ipv6h->daddr, 0);
1017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001019 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
1021 return 0;
1022}
1023
1024/* The socket must have it's spinlock held when we get
1025 * here.
1026 *
1027 * We have a potential double-lock case here, so even when
1028 * doing backlog processing we use the BH locking scheme.
1029 * This is because we cannot sleep with the original spinlock
1030 * held.
1031 */
1032static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1033{
1034 struct ipv6_pinfo *np = inet6_sk(sk);
1035 struct tcp_sock *tp;
1036 struct sk_buff *opt_skb = NULL;
1037
1038 /* Imagine: socket is IPv6. IPv4 packet arrives,
1039 goes to IPv4 receive handler and backlogged.
1040 From backlog it always goes here. Kerboom...
1041 Fortunately, tcp_rcv_established and rcv_established
1042 handle them correctly, but it is not case with
1043 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1044 */
1045
1046 if (skb->protocol == htons(ETH_P_IP))
1047 return tcp_v4_do_rcv(sk, skb);
1048
1049 if (sk_filter(sk, skb, 0))
1050 goto discard;
1051
1052 /*
1053 * socket locking is here for SMP purposes as backlog rcv
1054 * is currently called with bh processing disabled.
1055 */
1056
1057 /* Do Stevens' IPV6_PKTOPTIONS.
1058
1059 Yes, guys, it is the only place in our code, where we
1060 may make it not affecting IPv4.
1061 The rest of code is protocol independent,
1062 and I do not like idea to uglify IPv4.
1063
1064 Actually, all the idea behind IPV6_PKTOPTIONS
1065 looks not very well thought. For now we latch
1066 options, received in the last packet, enqueued
1067 by tcp. Feel free to propose better solution.
1068 --ANK (980728)
1069 */
1070 if (np->rxopt.all)
1071 opt_skb = skb_clone(skb, GFP_ATOMIC);
1072
1073 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1074 TCP_CHECK_TIMER(sk);
1075 if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
1076 goto reset;
1077 TCP_CHECK_TIMER(sk);
1078 if (opt_skb)
1079 goto ipv6_pktoptions;
1080 return 0;
1081 }
1082
1083 if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
1084 goto csum_err;
1085
1086 if (sk->sk_state == TCP_LISTEN) {
1087 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1088 if (!nsk)
1089 goto discard;
1090
1091 /*
1092 * Queue it on the new socket if the new socket is active,
1093 * otherwise we just shortcircuit this and continue with
1094 * the new socket..
1095 */
1096 if(nsk != sk) {
1097 if (tcp_child_process(sk, nsk, skb))
1098 goto reset;
1099 if (opt_skb)
1100 __kfree_skb(opt_skb);
1101 return 0;
1102 }
1103 }
1104
1105 TCP_CHECK_TIMER(sk);
1106 if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
1107 goto reset;
1108 TCP_CHECK_TIMER(sk);
1109 if (opt_skb)
1110 goto ipv6_pktoptions;
1111 return 0;
1112
1113reset:
1114 tcp_v6_send_reset(skb);
1115discard:
1116 if (opt_skb)
1117 __kfree_skb(opt_skb);
1118 kfree_skb(skb);
1119 return 0;
1120csum_err:
1121 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1122 goto discard;
1123
1124
1125ipv6_pktoptions:
1126 /* Do you ask, what is it?
1127
1128 1. skb was enqueued by tcp.
1129 2. skb is added to tail of read queue, rather than out of order.
1130 3. socket is not in passive state.
1131 4. Finally, it really contains options, which user wants to receive.
1132 */
1133 tp = tcp_sk(sk);
1134 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1135 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001136 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001137 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001138 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
1140 if (ipv6_opt_accepted(sk, opt_skb)) {
1141 skb_set_owner_r(opt_skb, sk);
1142 opt_skb = xchg(&np->pktoptions, opt_skb);
1143 } else {
1144 __kfree_skb(opt_skb);
1145 opt_skb = xchg(&np->pktoptions, NULL);
1146 }
1147 }
1148
1149 if (opt_skb)
1150 kfree_skb(opt_skb);
1151 return 0;
1152}
1153
1154static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
1155{
1156 struct sk_buff *skb = *pskb;
1157 struct tcphdr *th;
1158 struct sock *sk;
1159 int ret;
1160
1161 if (skb->pkt_type != PACKET_HOST)
1162 goto discard_it;
1163
1164 /*
1165 * Count it even if it's bad.
1166 */
1167 TCP_INC_STATS_BH(TCP_MIB_INSEGS);
1168
1169 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1170 goto discard_it;
1171
1172 th = skb->h.th;
1173
1174 if (th->doff < sizeof(struct tcphdr)/4)
1175 goto bad_packet;
1176 if (!pskb_may_pull(skb, th->doff*4))
1177 goto discard_it;
1178
1179 if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
Herbert Xufb286bb2005-11-10 13:01:24 -08001180 tcp_v6_checksum_init(skb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 goto bad_packet;
1182
1183 th = skb->h.th;
1184 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1185 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1186 skb->len - th->doff*4);
1187 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1188 TCP_SKB_CB(skb)->when = 0;
1189 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
1190 TCP_SKB_CB(skb)->sacked = 0;
1191
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001192 sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source,
1193 &skb->nh.ipv6h->daddr, ntohs(th->dest),
1194 inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196 if (!sk)
1197 goto no_tcp_socket;
1198
1199process:
1200 if (sk->sk_state == TCP_TIME_WAIT)
1201 goto do_time_wait;
1202
1203 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1204 goto discard_and_relse;
1205
1206 if (sk_filter(sk, skb, 0))
1207 goto discard_and_relse;
1208
1209 skb->dev = NULL;
1210
1211 bh_lock_sock(sk);
1212 ret = 0;
1213 if (!sock_owned_by_user(sk)) {
1214 if (!tcp_prequeue(sk, skb))
1215 ret = tcp_v6_do_rcv(sk, skb);
1216 } else
1217 sk_add_backlog(sk, skb);
1218 bh_unlock_sock(sk);
1219
1220 sock_put(sk);
1221 return ret ? -1 : 0;
1222
1223no_tcp_socket:
1224 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1225 goto discard_it;
1226
1227 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1228bad_packet:
1229 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1230 } else {
1231 tcp_v6_send_reset(skb);
1232 }
1233
1234discard_it:
1235
1236 /*
1237 * Discard frame
1238 */
1239
1240 kfree_skb(skb);
1241 return 0;
1242
1243discard_and_relse:
1244 sock_put(sk);
1245 goto discard_it;
1246
1247do_time_wait:
1248 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001249 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 goto discard_it;
1251 }
1252
1253 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1254 TCP_INC_STATS_BH(TCP_MIB_INERRS);
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001255 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 goto discard_it;
1257 }
1258
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001259 switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
1260 skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 case TCP_TW_SYN:
1262 {
1263 struct sock *sk2;
1264
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001265 sk2 = inet6_lookup_listener(&tcp_hashinfo,
1266 &skb->nh.ipv6h->daddr,
1267 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001269 struct inet_timewait_sock *tw = inet_twsk(sk);
1270 inet_twsk_deschedule(tw, &tcp_death_row);
1271 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 sk = sk2;
1273 goto process;
1274 }
1275 /* Fall through to ACK */
1276 }
1277 case TCP_TW_ACK:
1278 tcp_v6_timewait_ack(sk, skb);
1279 break;
1280 case TCP_TW_RST:
1281 goto no_tcp_socket;
1282 case TCP_TW_SUCCESS:;
1283 }
1284 goto discard_it;
1285}
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287static int tcp_v6_remember_stamp(struct sock *sk)
1288{
1289 /* Alas, not yet... */
1290 return 0;
1291}
1292
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001293static struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melob9750ce2005-12-13 23:22:54 -08001294 .queue_xmit = inet6_csk_xmit,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 .send_check = tcp_v6_send_check,
Arnaldo Carvalho de Melob9750ce2005-12-13 23:22:54 -08001296 .rebuild_header = inet6_sk_rebuild_header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 .conn_request = tcp_v6_conn_request,
1298 .syn_recv_sock = tcp_v6_syn_recv_sock,
1299 .remember_stamp = tcp_v6_remember_stamp,
1300 .net_header_len = sizeof(struct ipv6hdr),
1301
1302 .setsockopt = ipv6_setsockopt,
1303 .getsockopt = ipv6_getsockopt,
Arnaldo Carvalho de Melob9750ce2005-12-13 23:22:54 -08001304 .addr2sockaddr = inet6_csk_addr2sockaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 .sockaddr_len = sizeof(struct sockaddr_in6)
1306};
1307
1308/*
1309 * TCP over IPv4 via INET6 API
1310 */
1311
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001312static struct inet_connection_sock_af_ops ipv6_mapped = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 .queue_xmit = ip_queue_xmit,
1314 .send_check = tcp_v4_send_check,
Arnaldo Carvalho de Melo32519f12005-08-09 19:50:02 -07001315 .rebuild_header = inet_sk_rebuild_header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 .conn_request = tcp_v6_conn_request,
1317 .syn_recv_sock = tcp_v6_syn_recv_sock,
1318 .remember_stamp = tcp_v4_remember_stamp,
1319 .net_header_len = sizeof(struct iphdr),
1320
1321 .setsockopt = ipv6_setsockopt,
1322 .getsockopt = ipv6_getsockopt,
Arnaldo Carvalho de Melob9750ce2005-12-13 23:22:54 -08001323 .addr2sockaddr = inet6_csk_addr2sockaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 .sockaddr_len = sizeof(struct sockaddr_in6)
1325};
1326
1327
1328
1329/* NOTE: A lot of things set to zero explicitly by call to
1330 * sk_alloc() so need not be done here.
1331 */
1332static int tcp_v6_init_sock(struct sock *sk)
1333{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001334 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 struct tcp_sock *tp = tcp_sk(sk);
1336
1337 skb_queue_head_init(&tp->out_of_order_queue);
1338 tcp_init_xmit_timers(sk);
1339 tcp_prequeue_init(tp);
1340
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001341 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 tp->mdev = TCP_TIMEOUT_INIT;
1343
1344 /* So many TCP implementations out there (incorrectly) count the
1345 * initial SYN frame in their delayed-ACK and congestion control
1346 * algorithms that we must have the following bandaid to talk
1347 * efficiently to them. -DaveM
1348 */
1349 tp->snd_cwnd = 2;
1350
1351 /* See draft-stevens-tcpca-spec-01 for discussion of the
1352 * initialization of these values.
1353 */
1354 tp->snd_ssthresh = 0x7fffffff;
1355 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001356 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 tp->reordering = sysctl_tcp_reordering;
1359
1360 sk->sk_state = TCP_CLOSE;
1361
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001362 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001363 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 sk->sk_write_space = sk_stream_write_space;
1365 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1366
1367 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1368 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1369
1370 atomic_inc(&tcp_sockets_allocated);
1371
1372 return 0;
1373}
1374
1375static int tcp_v6_destroy_sock(struct sock *sk)
1376{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 tcp_v4_destroy_sock(sk);
1378 return inet6_destroy_sock(sk);
1379}
1380
1381/* Proc filesystem TCPv6 sock list dumping. */
1382static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001383 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001386 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1387 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389 if (ttd < 0)
1390 ttd = 0;
1391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 seq_printf(seq,
1393 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1394 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1395 i,
1396 src->s6_addr32[0], src->s6_addr32[1],
1397 src->s6_addr32[2], src->s6_addr32[3],
1398 ntohs(inet_sk(sk)->sport),
1399 dest->s6_addr32[0], dest->s6_addr32[1],
1400 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001401 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 TCP_SYN_RECV,
1403 0,0, /* could print option size, but that is af dependent. */
1404 1, /* timers active (only the expire timer) */
1405 jiffies_to_clock_t(ttd),
1406 req->retrans,
1407 uid,
1408 0, /* non standard timer */
1409 0, /* open_requests have no inode */
1410 0, req);
1411}
1412
1413static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1414{
1415 struct in6_addr *dest, *src;
1416 __u16 destp, srcp;
1417 int timer_active;
1418 unsigned long timer_expires;
1419 struct inet_sock *inet = inet_sk(sp);
1420 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001421 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 struct ipv6_pinfo *np = inet6_sk(sp);
1423
1424 dest = &np->daddr;
1425 src = &np->rcv_saddr;
1426 destp = ntohs(inet->dport);
1427 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001428
1429 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001431 timer_expires = icsk->icsk_timeout;
1432 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001434 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 } else if (timer_pending(&sp->sk_timer)) {
1436 timer_active = 2;
1437 timer_expires = sp->sk_timer.expires;
1438 } else {
1439 timer_active = 0;
1440 timer_expires = jiffies;
1441 }
1442
1443 seq_printf(seq,
1444 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1445 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
1446 i,
1447 src->s6_addr32[0], src->s6_addr32[1],
1448 src->s6_addr32[2], src->s6_addr32[3], srcp,
1449 dest->s6_addr32[0], dest->s6_addr32[1],
1450 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1451 sp->sk_state,
1452 tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
1453 timer_active,
1454 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001455 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001457 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 sock_i_ino(sp),
1459 atomic_read(&sp->sk_refcnt), sp,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001460 icsk->icsk_rto,
1461 icsk->icsk_ack.ato,
1462 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
1464 );
1465}
1466
1467static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001468 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469{
1470 struct in6_addr *dest, *src;
1471 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001472 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 int ttd = tw->tw_ttd - jiffies;
1474
1475 if (ttd < 0)
1476 ttd = 0;
1477
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001478 dest = &tw6->tw_v6_daddr;
1479 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 destp = ntohs(tw->tw_dport);
1481 srcp = ntohs(tw->tw_sport);
1482
1483 seq_printf(seq,
1484 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1485 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1486 i,
1487 src->s6_addr32[0], src->s6_addr32[1],
1488 src->s6_addr32[2], src->s6_addr32[3], srcp,
1489 dest->s6_addr32[0], dest->s6_addr32[1],
1490 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1491 tw->tw_substate, 0, 0,
1492 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1493 atomic_read(&tw->tw_refcnt), tw);
1494}
1495
1496#ifdef CONFIG_PROC_FS
1497static int tcp6_seq_show(struct seq_file *seq, void *v)
1498{
1499 struct tcp_iter_state *st;
1500
1501 if (v == SEQ_START_TOKEN) {
1502 seq_puts(seq,
1503 " sl "
1504 "local_address "
1505 "remote_address "
1506 "st tx_queue rx_queue tr tm->when retrnsmt"
1507 " uid timeout inode\n");
1508 goto out;
1509 }
1510 st = seq->private;
1511
1512 switch (st->state) {
1513 case TCP_SEQ_STATE_LISTENING:
1514 case TCP_SEQ_STATE_ESTABLISHED:
1515 get_tcp6_sock(seq, v, st->num);
1516 break;
1517 case TCP_SEQ_STATE_OPENREQ:
1518 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
1519 break;
1520 case TCP_SEQ_STATE_TIME_WAIT:
1521 get_timewait6_sock(seq, v, st->num);
1522 break;
1523 }
1524out:
1525 return 0;
1526}
1527
1528static struct file_operations tcp6_seq_fops;
1529static struct tcp_seq_afinfo tcp6_seq_afinfo = {
1530 .owner = THIS_MODULE,
1531 .name = "tcp6",
1532 .family = AF_INET6,
1533 .seq_show = tcp6_seq_show,
1534 .seq_fops = &tcp6_seq_fops,
1535};
1536
1537int __init tcp6_proc_init(void)
1538{
1539 return tcp_proc_register(&tcp6_seq_afinfo);
1540}
1541
1542void tcp6_proc_exit(void)
1543{
1544 tcp_proc_unregister(&tcp6_seq_afinfo);
1545}
1546#endif
1547
1548struct proto tcpv6_prot = {
1549 .name = "TCPv6",
1550 .owner = THIS_MODULE,
1551 .close = tcp_close,
1552 .connect = tcp_v6_connect,
1553 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001554 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 .ioctl = tcp_ioctl,
1556 .init = tcp_v6_init_sock,
1557 .destroy = tcp_v6_destroy_sock,
1558 .shutdown = tcp_shutdown,
1559 .setsockopt = tcp_setsockopt,
1560 .getsockopt = tcp_getsockopt,
1561 .sendmsg = tcp_sendmsg,
1562 .recvmsg = tcp_recvmsg,
1563 .backlog_rcv = tcp_v6_do_rcv,
1564 .hash = tcp_v6_hash,
1565 .unhash = tcp_unhash,
1566 .get_port = tcp_v6_get_port,
1567 .enter_memory_pressure = tcp_enter_memory_pressure,
1568 .sockets_allocated = &tcp_sockets_allocated,
1569 .memory_allocated = &tcp_memory_allocated,
1570 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07001571 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 .sysctl_mem = sysctl_tcp_mem,
1573 .sysctl_wmem = sysctl_tcp_wmem,
1574 .sysctl_rmem = sysctl_tcp_rmem,
1575 .max_header = MAX_TCP_HEADER,
1576 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08001577 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001578 .rsk_prot = &tcp6_request_sock_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579};
1580
1581static struct inet6_protocol tcpv6_protocol = {
1582 .handler = tcp_v6_rcv,
1583 .err_handler = tcp_v6_err,
1584 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1585};
1586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587static struct inet_protosw tcpv6_protosw = {
1588 .type = SOCK_STREAM,
1589 .protocol = IPPROTO_TCP,
1590 .prot = &tcpv6_prot,
1591 .ops = &inet6_stream_ops,
1592 .capability = -1,
1593 .no_check = 0,
1594 .flags = INET_PROTOSW_PERMANENT,
1595};
1596
1597void __init tcpv6_init(void)
1598{
1599 /* register inet6 protocol */
1600 if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
1601 printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
1602 inet6_register_protosw(&tcpv6_protosw);
1603}