blob: 8ce8a1359d2b030d4d2756e6a9d68781758bdd9d [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>
63
64#include <asm/uaccess.h>
65
66#include <linux/proc_fs.h>
67#include <linux/seq_file.h>
68
69static void tcp_v6_send_reset(struct sk_buff *skb);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -070070static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080071static void tcp_v6_send_check(struct sock *sk, int len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 struct sk_buff *skb);
73
74static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
75static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok);
76
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
Arnaldo Carvalho de Melo971af182005-12-13 23:14:47 -080080int inet6_csk_bind_conflict(const struct sock *sk,
81 const struct inet_bind_bucket *tb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{
Arnaldo Carvalho de Melo0f7ff922005-08-09 19:59:44 -070083 const struct sock *sk2;
84 const struct hlist_node *node;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86 /* We must walk the whole port owner list in this case. -DaveM */
87 sk_for_each_bound(sk2, node, &tb->owners) {
88 if (sk != sk2 &&
89 (!sk->sk_bound_dev_if ||
90 !sk2->sk_bound_dev_if ||
91 sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
92 (!sk->sk_reuse || !sk2->sk_reuse ||
93 sk2->sk_state == TCP_LISTEN) &&
94 ipv6_rcv_saddr_equal(sk, sk2))
95 break;
96 }
97
98 return node != NULL;
99}
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
102{
Arnaldo Carvalho de Melo971af182005-12-13 23:14:47 -0800103 return inet_csk_get_port(&tcp_hashinfo, sk, snum,
104 inet6_csk_bind_conflict);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105}
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107static void tcp_v6_hash(struct sock *sk)
108{
109 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800110 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 tcp_prot.hash(sk);
112 return;
113 }
114 local_bh_disable();
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -0800115 __inet6_hash(&tcp_hashinfo, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 local_bh_enable();
117 }
118}
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
121 struct in6_addr *saddr,
122 struct in6_addr *daddr,
123 unsigned long base)
124{
125 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
126}
127
128static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
129{
130 if (skb->protocol == htons(ETH_P_IPV6)) {
131 return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
132 skb->nh.ipv6h->saddr.s6_addr32,
133 skb->h.th->dest,
134 skb->h.th->source);
135 } else {
136 return secure_tcp_sequence_number(skb->nh.iph->daddr,
137 skb->nh.iph->saddr,
138 skb->h.th->dest,
139 skb->h.th->source);
140 }
141}
142
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300143static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700144 struct inet_timewait_sock **twp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
146 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300147 const struct ipv6_pinfo *np = inet6_sk(sk);
148 const struct in6_addr *daddr = &np->rcv_saddr;
149 const struct in6_addr *saddr = &np->daddr;
150 const int dif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700151 const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
Eric Dumazet81c3d542005-10-03 14:13:38 -0700152 unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport);
153 struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 struct sock *sk2;
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700155 const struct hlist_node *node;
156 struct inet_timewait_sock *tw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Eric Dumazet81c3d542005-10-03 14:13:38 -0700158 prefetch(head->chain.first);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 write_lock(&head->lock);
160
161 /* Check TIME-WAIT sockets first. */
Arnaldo Carvalho de Melo6e04e022005-08-09 20:07:35 -0700162 sk_for_each(sk2, node, &(head + tcp_hashinfo.ehash_size)->chain) {
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700163 const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk2);
164
165 tw = inet_twsk(sk2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 if(*((__u32 *)&(tw->tw_dport)) == ports &&
168 sk2->sk_family == PF_INET6 &&
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700169 ipv6_addr_equal(&tcp6tw->tw_v6_daddr, saddr) &&
170 ipv6_addr_equal(&tcp6tw->tw_v6_rcv_saddr, daddr) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 sk2->sk_bound_dev_if == sk->sk_bound_dev_if) {
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700172 const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 struct tcp_sock *tp = tcp_sk(sk);
174
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700175 if (tcptw->tw_ts_recent_stamp &&
176 (!twp ||
177 (sysctl_tcp_tw_reuse &&
178 xtime.tv_sec - tcptw->tw_ts_recent_stamp > 1))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 /* See comment in tcp_ipv4.c */
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700180 tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 if (!tp->write_seq)
182 tp->write_seq = 1;
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700183 tp->rx_opt.ts_recent = tcptw->tw_ts_recent;
184 tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 sock_hold(sk2);
186 goto unique;
187 } else
188 goto not_unique;
189 }
190 }
191 tw = NULL;
192
193 /* And established part... */
194 sk_for_each(sk2, node, &head->chain) {
Eric Dumazet81c3d542005-10-03 14:13:38 -0700195 if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 goto not_unique;
197 }
198
199unique:
200 BUG_TRAP(sk_unhashed(sk));
201 __sk_add_node(sk, &head->chain);
Eric Dumazet81c3d542005-10-03 14:13:38 -0700202 sk->sk_hash = hash;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 sock_prot_inc_use(sk->sk_prot);
204 write_unlock(&head->lock);
205
206 if (twp) {
207 *twp = tw;
208 NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
209 } else if (tw) {
210 /* Silly. Should hash-dance instead... */
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -0700211 inet_twsk_deschedule(tw, &tcp_death_row);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
213
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700214 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 }
216 return 0;
217
218not_unique:
219 write_unlock(&head->lock);
220 return -EADDRNOTAVAIL;
221}
222
223static inline u32 tcpv6_port_offset(const struct sock *sk)
224{
225 const struct inet_sock *inet = inet_sk(sk);
226 const struct ipv6_pinfo *np = inet6_sk(sk);
227
228 return secure_tcpv6_port_ephemeral(np->rcv_saddr.s6_addr32,
229 np->daddr.s6_addr32,
230 inet->dport);
231}
232
233static int tcp_v6_hash_connect(struct sock *sk)
234{
235 unsigned short snum = inet_sk(sk)->num;
Arnaldo Carvalho de Melo0f7ff922005-08-09 19:59:44 -0700236 struct inet_bind_hashbucket *head;
237 struct inet_bind_bucket *tb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 int ret;
239
240 if (!snum) {
241 int low = sysctl_local_port_range[0];
242 int high = sysctl_local_port_range[1];
243 int range = high - low;
244 int i;
245 int port;
246 static u32 hint;
247 u32 offset = hint + tcpv6_port_offset(sk);
248 struct hlist_node *node;
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700249 struct inet_timewait_sock *tw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 local_bh_disable();
252 for (i = 1; i <= range; i++) {
253 port = low + (i + offset) % range;
Arnaldo Carvalho de Melo6e04e022005-08-09 20:07:35 -0700254 head = &tcp_hashinfo.bhash[inet_bhashfn(port, tcp_hashinfo.bhash_size)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 spin_lock(&head->lock);
256
257 /* Does not bother with rcv_saddr checks,
258 * because the established check is already
259 * unique enough.
260 */
Arnaldo Carvalho de Melo0f7ff922005-08-09 19:59:44 -0700261 inet_bind_bucket_for_each(tb, node, &head->chain) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 if (tb->port == port) {
263 BUG_TRAP(!hlist_empty(&tb->owners));
264 if (tb->fastreuse >= 0)
265 goto next_port;
266 if (!__tcp_v6_check_established(sk,
267 port,
268 &tw))
269 goto ok;
270 goto next_port;
271 }
272 }
273
Arnaldo Carvalho de Melo6e04e022005-08-09 20:07:35 -0700274 tb = inet_bind_bucket_create(tcp_hashinfo.bind_bucket_cachep, head, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 if (!tb) {
276 spin_unlock(&head->lock);
277 break;
278 }
279 tb->fastreuse = -1;
280 goto ok;
281
282 next_port:
283 spin_unlock(&head->lock);
284 }
285 local_bh_enable();
286
287 return -EADDRNOTAVAIL;
288
289ok:
290 hint += i;
291
292 /* Head lock still held and bh's disabled */
Arnaldo Carvalho de Melo2d8c4ce2005-08-09 20:07:13 -0700293 inet_bind_hash(sk, tb, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (sk_unhashed(sk)) {
295 inet_sk(sk)->sport = htons(port);
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -0800296 __inet6_hash(&tcp_hashinfo, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298 spin_unlock(&head->lock);
299
300 if (tw) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -0700301 inet_twsk_deschedule(tw, &tcp_death_row);
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700302 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
304
305 ret = 0;
306 goto out;
307 }
308
Arnaldo Carvalho de Melo6e04e022005-08-09 20:07:35 -0700309 head = &tcp_hashinfo.bhash[inet_bhashfn(snum, tcp_hashinfo.bhash_size)];
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700310 tb = inet_csk(sk)->icsk_bind_hash;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 spin_lock_bh(&head->lock);
312
313 if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -0800314 __inet6_hash(&tcp_hashinfo, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 spin_unlock_bh(&head->lock);
316 return 0;
317 } else {
318 spin_unlock(&head->lock);
319 /* No definite answer... Walk to established hash table */
320 ret = __tcp_v6_check_established(sk, snum, NULL);
321out:
322 local_bh_enable();
323 return ret;
324 }
325}
326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
328 int addr_len)
329{
330 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
331 struct inet_sock *inet = inet_sk(sk);
332 struct ipv6_pinfo *np = inet6_sk(sk);
333 struct tcp_sock *tp = tcp_sk(sk);
334 struct in6_addr *saddr = NULL, *final_p = NULL, final;
335 struct flowi fl;
336 struct dst_entry *dst;
337 int addr_type;
338 int err;
339
340 if (addr_len < SIN6_LEN_RFC2133)
341 return -EINVAL;
342
343 if (usin->sin6_family != AF_INET6)
344 return(-EAFNOSUPPORT);
345
346 memset(&fl, 0, sizeof(fl));
347
348 if (np->sndflow) {
349 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
350 IP6_ECN_flow_init(fl.fl6_flowlabel);
351 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
352 struct ip6_flowlabel *flowlabel;
353 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
354 if (flowlabel == NULL)
355 return -EINVAL;
356 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
357 fl6_sock_release(flowlabel);
358 }
359 }
360
361 /*
362 * connect() to INADDR_ANY means loopback (BSD'ism).
363 */
364
365 if(ipv6_addr_any(&usin->sin6_addr))
366 usin->sin6_addr.s6_addr[15] = 0x1;
367
368 addr_type = ipv6_addr_type(&usin->sin6_addr);
369
370 if(addr_type & IPV6_ADDR_MULTICAST)
371 return -ENETUNREACH;
372
373 if (addr_type&IPV6_ADDR_LINKLOCAL) {
374 if (addr_len >= sizeof(struct sockaddr_in6) &&
375 usin->sin6_scope_id) {
376 /* If interface is set while binding, indices
377 * must coincide.
378 */
379 if (sk->sk_bound_dev_if &&
380 sk->sk_bound_dev_if != usin->sin6_scope_id)
381 return -EINVAL;
382
383 sk->sk_bound_dev_if = usin->sin6_scope_id;
384 }
385
386 /* Connect to link-local address requires an interface */
387 if (!sk->sk_bound_dev_if)
388 return -EINVAL;
389 }
390
391 if (tp->rx_opt.ts_recent_stamp &&
392 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
393 tp->rx_opt.ts_recent = 0;
394 tp->rx_opt.ts_recent_stamp = 0;
395 tp->write_seq = 0;
396 }
397
398 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
399 np->flow_label = fl.fl6_flowlabel;
400
401 /*
402 * TCP over IPv4
403 */
404
405 if (addr_type == IPV6_ADDR_MAPPED) {
406 u32 exthdrlen = tp->ext_header_len;
407 struct sockaddr_in sin;
408
409 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
410
411 if (__ipv6_only_sock(sk))
412 return -ENETUNREACH;
413
414 sin.sin_family = AF_INET;
415 sin.sin_port = usin->sin6_port;
416 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
417
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800418 inet_csk(sk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 sk->sk_backlog_rcv = tcp_v4_do_rcv;
420
421 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
422
423 if (err) {
424 tp->ext_header_len = exthdrlen;
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800425 inet_csk(sk)->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 sk->sk_backlog_rcv = tcp_v6_do_rcv;
427 goto failure;
428 } else {
429 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
430 inet->saddr);
431 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
432 inet->rcv_saddr);
433 }
434
435 return err;
436 }
437
438 if (!ipv6_addr_any(&np->rcv_saddr))
439 saddr = &np->rcv_saddr;
440
441 fl.proto = IPPROTO_TCP;
442 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
443 ipv6_addr_copy(&fl.fl6_src,
444 (saddr ? saddr : &np->saddr));
445 fl.oif = sk->sk_bound_dev_if;
446 fl.fl_ip_dport = usin->sin6_port;
447 fl.fl_ip_sport = inet->sport;
448
449 if (np->opt && np->opt->srcrt) {
450 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
451 ipv6_addr_copy(&final, &fl.fl6_dst);
452 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
453 final_p = &final;
454 }
455
456 err = ip6_dst_lookup(sk, &dst, &fl);
457 if (err)
458 goto failure;
459 if (final_p)
460 ipv6_addr_copy(&fl.fl6_dst, final_p);
461
Patrick McHardye104411b2005-09-08 15:11:55 -0700462 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 if (saddr == NULL) {
466 saddr = &fl.fl6_src;
467 ipv6_addr_copy(&np->rcv_saddr, saddr);
468 }
469
470 /* set the source address */
471 ipv6_addr_copy(&np->saddr, saddr);
472 inet->rcv_saddr = LOOPBACK4_IPV6;
473
474 ip6_dst_store(sk, dst, NULL);
475 sk->sk_route_caps = dst->dev->features &
476 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
477
478 tp->ext_header_len = 0;
479 if (np->opt)
480 tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
481
482 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
483
484 inet->dport = usin->sin6_port;
485
486 tcp_set_state(sk, TCP_SYN_SENT);
487 err = tcp_v6_hash_connect(sk);
488 if (err)
489 goto late_failure;
490
491 if (!tp->write_seq)
492 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
493 np->daddr.s6_addr32,
494 inet->sport,
495 inet->dport);
496
497 err = tcp_connect(sk);
498 if (err)
499 goto late_failure;
500
501 return 0;
502
503late_failure:
504 tcp_set_state(sk, TCP_CLOSE);
505 __sk_dst_reset(sk);
506failure:
507 inet->dport = 0;
508 sk->sk_route_caps = 0;
509 return err;
510}
511
512static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
513 int type, int code, int offset, __u32 info)
514{
515 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300516 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 struct ipv6_pinfo *np;
518 struct sock *sk;
519 int err;
520 struct tcp_sock *tp;
521 __u32 seq;
522
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300523 sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
524 th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526 if (sk == NULL) {
527 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
528 return;
529 }
530
531 if (sk->sk_state == TCP_TIME_WAIT) {
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700532 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 return;
534 }
535
536 bh_lock_sock(sk);
537 if (sock_owned_by_user(sk))
538 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
539
540 if (sk->sk_state == TCP_CLOSE)
541 goto out;
542
543 tp = tcp_sk(sk);
544 seq = ntohl(th->seq);
545 if (sk->sk_state != TCP_LISTEN &&
546 !between(seq, tp->snd_una, tp->snd_nxt)) {
547 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
548 goto out;
549 }
550
551 np = inet6_sk(sk);
552
553 if (type == ICMPV6_PKT_TOOBIG) {
554 struct dst_entry *dst = NULL;
555
556 if (sock_owned_by_user(sk))
557 goto out;
558 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
559 goto out;
560
561 /* icmp should have updated the destination cache entry */
562 dst = __sk_dst_check(sk, np->dst_cookie);
563
564 if (dst == NULL) {
565 struct inet_sock *inet = inet_sk(sk);
566 struct flowi fl;
567
568 /* BUGGG_FUTURE: Again, it is not clear how
569 to handle rthdr case. Ignore this complexity
570 for now.
571 */
572 memset(&fl, 0, sizeof(fl));
573 fl.proto = IPPROTO_TCP;
574 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
575 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
576 fl.oif = sk->sk_bound_dev_if;
577 fl.fl_ip_dport = inet->dport;
578 fl.fl_ip_sport = inet->sport;
579
580 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
581 sk->sk_err_soft = -err;
582 goto out;
583 }
584
585 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
586 sk->sk_err_soft = -err;
587 goto out;
588 }
589
590 } else
591 dst_hold(dst);
592
593 if (tp->pmtu_cookie > dst_mtu(dst)) {
594 tcp_sync_mss(sk, dst_mtu(dst));
595 tcp_simple_retransmit(sk);
596 } /* else let the usual retransmit timer handle it */
597 dst_release(dst);
598 goto out;
599 }
600
601 icmpv6_err_convert(type, code, &err);
602
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700603 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700605 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 case TCP_LISTEN:
607 if (sock_owned_by_user(sk))
608 goto out;
609
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800610 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
611 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (!req)
613 goto out;
614
615 /* ICMPs are not backlogged, hence we cannot get
616 * an established socket here.
617 */
618 BUG_TRAP(req->sk == NULL);
619
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700620 if (seq != tcp_rsk(req)->snt_isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
622 goto out;
623 }
624
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700625 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 goto out;
627
628 case TCP_SYN_SENT:
629 case TCP_SYN_RECV: /* Cannot happen.
630 It can, it SYNs are crossed. --ANK */
631 if (!sock_owned_by_user(sk)) {
632 TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
633 sk->sk_err = err;
634 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
635
636 tcp_done(sk);
637 } else
638 sk->sk_err_soft = err;
639 goto out;
640 }
641
642 if (!sock_owned_by_user(sk) && np->recverr) {
643 sk->sk_err = err;
644 sk->sk_error_report(sk);
645 } else
646 sk->sk_err_soft = err;
647
648out:
649 bh_unlock_sock(sk);
650 sock_put(sk);
651}
652
653
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700654static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 struct dst_entry *dst)
656{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800657 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 struct ipv6_pinfo *np = inet6_sk(sk);
659 struct sk_buff * skb;
660 struct ipv6_txoptions *opt = NULL;
661 struct in6_addr * final_p = NULL, final;
662 struct flowi fl;
663 int err = -1;
664
665 memset(&fl, 0, sizeof(fl));
666 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700667 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
668 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700670 fl.oif = treq->iif;
671 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 fl.fl_ip_sport = inet_sk(sk)->sport;
673
674 if (dst == NULL) {
675 opt = np->opt;
676 if (opt == NULL &&
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900677 np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700678 treq->pktopts) {
679 struct sk_buff *pktopts = treq->pktopts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 struct inet6_skb_parm *rxopt = IP6CB(pktopts);
681 if (rxopt->srcrt)
682 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt));
683 }
684
685 if (opt && opt->srcrt) {
686 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
687 ipv6_addr_copy(&final, &fl.fl6_dst);
688 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
689 final_p = &final;
690 }
691
692 err = ip6_dst_lookup(sk, &dst, &fl);
693 if (err)
694 goto done;
695 if (final_p)
696 ipv6_addr_copy(&fl.fl6_dst, final_p);
697 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
698 goto done;
699 }
700
701 skb = tcp_make_synack(sk, dst, req);
702 if (skb) {
703 struct tcphdr *th = skb->h.th;
704
705 th->check = tcp_v6_check(th, skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700706 &treq->loc_addr, &treq->rmt_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 csum_partial((char *)th, skb->len, skb->csum));
708
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700709 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 err = ip6_xmit(sk, skb, &fl, opt, 0);
711 if (err == NET_XMIT_CN)
712 err = 0;
713 }
714
715done:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if (opt && opt != np->opt)
717 sock_kfree_s(sk, opt, opt->tot_len);
718 return err;
719}
720
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700721static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800723 if (inet6_rsk(req)->pktopts)
724 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725}
726
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700727static struct request_sock_ops tcp6_request_sock_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700729 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700731 .send_ack = tcp_v6_reqsk_send_ack,
732 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 .send_reset = tcp_v6_send_reset
734};
735
736static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
737{
738 struct ipv6_pinfo *np = inet6_sk(sk);
739 struct inet6_skb_parm *opt = IP6CB(skb);
740
741 if (np->rxopt.all) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900742 if ((opt->hop && (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) ||
743 ((IPV6_FLOWINFO_MASK & *(u32*)skb->nh.raw) && np->rxopt.bits.rxflow) ||
744 (opt->srcrt && (np->rxopt.bits.srcrt || np->rxopt.bits.osrcrt)) ||
745 ((opt->dst1 || opt->dst0) && (np->rxopt.bits.dstopts || np->rxopt.bits.odstopts)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return 1;
747 }
748 return 0;
749}
750
751
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800752static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
754 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800755 struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757 if (skb->ip_summed == CHECKSUM_HW) {
758 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
759 skb->csum = offsetof(struct tcphdr, check);
760 } else {
761 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
762 csum_partial((char *)th, th->doff<<2,
763 skb->csum));
764 }
765}
766
767
768static void tcp_v6_send_reset(struct sk_buff *skb)
769{
770 struct tcphdr *th = skb->h.th, *t1;
771 struct sk_buff *buff;
772 struct flowi fl;
773
774 if (th->rst)
775 return;
776
777 if (!ipv6_unicast_destination(skb))
778 return;
779
780 /*
781 * We need to grab some memory, and put together an RST,
782 * and then put it into the queue to be sent.
783 */
784
785 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr),
786 GFP_ATOMIC);
787 if (buff == NULL)
788 return;
789
790 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
791
792 t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
793
794 /* Swap the send and the receive. */
795 memset(t1, 0, sizeof(*t1));
796 t1->dest = th->source;
797 t1->source = th->dest;
798 t1->doff = sizeof(*t1)/4;
799 t1->rst = 1;
800
801 if(th->ack) {
802 t1->seq = th->ack_seq;
803 } else {
804 t1->ack = 1;
805 t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
806 + skb->len - (th->doff<<2));
807 }
808
809 buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
810
811 memset(&fl, 0, sizeof(fl));
812 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
813 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
814
815 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
816 sizeof(*t1), IPPROTO_TCP,
817 buff->csum);
818
819 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300820 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 fl.fl_ip_dport = t1->dest;
822 fl.fl_ip_sport = t1->source;
823
824 /* sk = NULL, but it is safe for now. RST socket required. */
825 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
826
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800827 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
828 ip6_xmit(NULL, buff, &fl, NULL, 0);
829 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
830 TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834
835 kfree_skb(buff);
836}
837
838static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
839{
840 struct tcphdr *th = skb->h.th, *t1;
841 struct sk_buff *buff;
842 struct flowi fl;
843 int tot_len = sizeof(struct tcphdr);
844
845 if (ts)
846 tot_len += 3*4;
847
848 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
849 GFP_ATOMIC);
850 if (buff == NULL)
851 return;
852
853 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
854
855 t1 = (struct tcphdr *) skb_push(buff,tot_len);
856
857 /* Swap the send and the receive. */
858 memset(t1, 0, sizeof(*t1));
859 t1->dest = th->source;
860 t1->source = th->dest;
861 t1->doff = tot_len/4;
862 t1->seq = htonl(seq);
863 t1->ack_seq = htonl(ack);
864 t1->ack = 1;
865 t1->window = htons(win);
866
867 if (ts) {
868 u32 *ptr = (u32*)(t1 + 1);
869 *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
870 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
871 *ptr++ = htonl(tcp_time_stamp);
872 *ptr = htonl(ts);
873 }
874
875 buff->csum = csum_partial((char *)t1, tot_len, 0);
876
877 memset(&fl, 0, sizeof(fl));
878 ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
879 ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
880
881 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
882 tot_len, IPPROTO_TCP,
883 buff->csum);
884
885 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300886 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 fl.fl_ip_dport = t1->dest;
888 fl.fl_ip_sport = t1->source;
889
890 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800891 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
892 ip6_xmit(NULL, buff, &fl, NULL, 0);
893 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -0800895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
897
898 kfree_skb(buff);
899}
900
901static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
902{
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700903 struct inet_timewait_sock *tw = inet_twsk(sk);
904 const struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700906 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
907 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
908 tcptw->tw_ts_recent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700910 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911}
912
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700913static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700915 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 -0700916}
917
918
919static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
920{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700921 struct request_sock *req, **prev;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300922 const struct tcphdr *th = skb->h.th;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 struct sock *nsk;
924
925 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800926 req = inet6_csk_search_req(sk, &prev, th->source,
927 &skb->nh.ipv6h->saddr,
928 &skb->nh.ipv6h->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if (req)
930 return tcp_check_req(sk, skb, req, prev);
931
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300932 nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr,
933 th->source, &skb->nh.ipv6h->daddr,
934 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 if (nsk) {
937 if (nsk->sk_state != TCP_TIME_WAIT) {
938 bh_lock_sock(nsk);
939 return nsk;
940 }
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -0700941 inet_twsk_put((struct inet_timewait_sock *)nsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 return NULL;
943 }
944
945#if 0 /*def CONFIG_SYN_COOKIES*/
946 if (!th->rst && !th->syn && th->ack)
947 sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
948#endif
949 return sk;
950}
951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952/* FIXME: this is substantially similar to the ipv4 code.
953 * Can some kind of merge be done? -- erics
954 */
955static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
956{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800957 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 struct ipv6_pinfo *np = inet6_sk(sk);
959 struct tcp_options_received tmp_opt;
960 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700961 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 __u32 isn = TCP_SKB_CB(skb)->when;
963
964 if (skb->protocol == htons(ETH_P_IP))
965 return tcp_v4_conn_request(sk, skb);
966
967 if (!ipv6_unicast_destination(skb))
968 goto drop;
969
970 /*
971 * There are no SYN attacks on IPv6, yet...
972 */
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700973 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 if (net_ratelimit())
975 printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
976 goto drop;
977 }
978
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700979 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 goto drop;
981
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800982 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (req == NULL)
984 goto drop;
985
986 tcp_clear_options(&tmp_opt);
987 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
988 tmp_opt.user_mss = tp->rx_opt.user_mss;
989
990 tcp_parse_options(skb, &tmp_opt, 0);
991
992 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
993 tcp_openreq_init(req, &tmp_opt, skb);
994
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800995 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700996 ipv6_addr_copy(&treq->rmt_addr, &skb->nh.ipv6h->saddr);
997 ipv6_addr_copy(&treq->loc_addr, &skb->nh.ipv6h->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 TCP_ECN_create_request(req, skb->h.th);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700999 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (ipv6_opt_accepted(sk, skb) ||
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001001 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1002 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 atomic_inc(&skb->users);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001004 treq->pktopts = skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001006 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 /* So that link locals have meaning */
1009 if (!sk->sk_bound_dev_if &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001010 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001011 treq->iif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013 if (isn == 0)
1014 isn = tcp_v6_init_sequence(sk,skb);
1015
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001016 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 if (tcp_v6_send_synack(sk, req, NULL))
1019 goto drop;
1020
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001021 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return 0;
1023
1024drop:
1025 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001026 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
1028 TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
1029 return 0; /* don't send reset */
1030}
1031
1032static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001033 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 struct dst_entry *dst)
1035{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001036 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1038 struct tcp6_sock *newtcp6sk;
1039 struct inet_sock *newinet;
1040 struct tcp_sock *newtp;
1041 struct sock *newsk;
1042 struct ipv6_txoptions *opt;
1043
1044 if (skb->protocol == htons(ETH_P_IP)) {
1045 /*
1046 * v6 mapped
1047 */
1048
1049 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1050
1051 if (newsk == NULL)
1052 return NULL;
1053
1054 newtcp6sk = (struct tcp6_sock *)newsk;
1055 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1056
1057 newinet = inet_sk(newsk);
1058 newnp = inet6_sk(newsk);
1059 newtp = tcp_sk(newsk);
1060
1061 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1062
1063 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
1064 newinet->daddr);
1065
1066 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
1067 newinet->saddr);
1068
1069 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1070
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001071 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
1073 newnp->pktoptions = NULL;
1074 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001075 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
1077
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001078 /*
1079 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1080 * here, tcp_create_openreq_child now does this for us, see the comment in
1081 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001085 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 Sync it now.
1087 */
1088 tcp_sync_mss(newsk, newtp->pmtu_cookie);
1089
1090 return newsk;
1091 }
1092
1093 opt = np->opt;
1094
1095 if (sk_acceptq_is_full(sk))
1096 goto out_overflow;
1097
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001098 if (np->rxopt.bits.osrcrt == 2 &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001099 opt == NULL && treq->pktopts) {
1100 struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 if (rxopt->srcrt)
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001102 opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr *)(treq->pktopts->nh.raw + rxopt->srcrt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 }
1104
1105 if (dst == NULL) {
1106 struct in6_addr *final_p = NULL, final;
1107 struct flowi fl;
1108
1109 memset(&fl, 0, sizeof(fl));
1110 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001111 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (opt && opt->srcrt) {
1113 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
1114 ipv6_addr_copy(&final, &fl.fl6_dst);
1115 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1116 final_p = &final;
1117 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001118 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001120 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 fl.fl_ip_sport = inet_sk(sk)->sport;
1122
1123 if (ip6_dst_lookup(sk, &dst, &fl))
1124 goto out;
1125
1126 if (final_p)
1127 ipv6_addr_copy(&fl.fl6_dst, final_p);
1128
1129 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
1130 goto out;
1131 }
1132
1133 newsk = tcp_create_openreq_child(sk, req, skb);
1134 if (newsk == NULL)
1135 goto out;
1136
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001137 /*
1138 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1139 * count here, tcp_create_openreq_child now does this for us, see the
1140 * comment in that function for the gory details. -acme
1141 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
1143 ip6_dst_store(newsk, dst, NULL);
1144 newsk->sk_route_caps = dst->dev->features &
1145 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
1146
1147 newtcp6sk = (struct tcp6_sock *)newsk;
1148 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1149
1150 newtp = tcp_sk(newsk);
1151 newinet = inet_sk(newsk);
1152 newnp = inet6_sk(newsk);
1153
1154 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1155
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001156 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1157 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1158 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1159 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
1161 /* Now IPv6 options...
1162
1163 First: no IPv4 options.
1164 */
1165 newinet->opt = NULL;
1166
1167 /* Clone RX bits */
1168 newnp->rxopt.all = np->rxopt.all;
1169
1170 /* Clone pktoptions received with SYN */
1171 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001172 if (treq->pktopts != NULL) {
1173 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1174 kfree_skb(treq->pktopts);
1175 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (newnp->pktoptions)
1177 skb_set_owner_r(newnp->pktoptions, newsk);
1178 }
1179 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001180 newnp->mcast_oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
1182
1183 /* Clone native IPv6 options from listening socket (if any)
1184
1185 Yes, keeping reference count would be much more clever,
1186 but we make one more one thing there: reattach optmem
1187 to newsk.
1188 */
1189 if (opt) {
1190 newnp->opt = ipv6_dup_options(newsk, opt);
1191 if (opt != np->opt)
1192 sock_kfree_s(sk, opt, opt->tot_len);
1193 }
1194
1195 newtp->ext_header_len = 0;
1196 if (newnp->opt)
1197 newtp->ext_header_len = newnp->opt->opt_nflen +
1198 newnp->opt->opt_flen;
1199
1200 tcp_sync_mss(newsk, dst_mtu(dst));
1201 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1202 tcp_initialize_rcv_mss(newsk);
1203
1204 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
1205
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -08001206 __inet6_hash(&tcp_hashinfo, newsk);
Arnaldo Carvalho de Melo2d8c4ce2005-08-09 20:07:13 -07001207 inet_inherit_port(&tcp_hashinfo, sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209 return newsk;
1210
1211out_overflow:
1212 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
1213out:
1214 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
1215 if (opt && opt != np->opt)
1216 sock_kfree_s(sk, opt, opt->tot_len);
1217 dst_release(dst);
1218 return NULL;
1219}
1220
1221static int tcp_v6_checksum_init(struct sk_buff *skb)
1222{
1223 if (skb->ip_summed == CHECKSUM_HW) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
Herbert Xufb286bb2005-11-10 13:01:24 -08001225 &skb->nh.ipv6h->daddr,skb->csum)) {
1226 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001230
1231 skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
1232 &skb->nh.ipv6h->daddr, 0);
1233
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001235 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 }
1237 return 0;
1238}
1239
1240/* The socket must have it's spinlock held when we get
1241 * here.
1242 *
1243 * We have a potential double-lock case here, so even when
1244 * doing backlog processing we use the BH locking scheme.
1245 * This is because we cannot sleep with the original spinlock
1246 * held.
1247 */
1248static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1249{
1250 struct ipv6_pinfo *np = inet6_sk(sk);
1251 struct tcp_sock *tp;
1252 struct sk_buff *opt_skb = NULL;
1253
1254 /* Imagine: socket is IPv6. IPv4 packet arrives,
1255 goes to IPv4 receive handler and backlogged.
1256 From backlog it always goes here. Kerboom...
1257 Fortunately, tcp_rcv_established and rcv_established
1258 handle them correctly, but it is not case with
1259 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1260 */
1261
1262 if (skb->protocol == htons(ETH_P_IP))
1263 return tcp_v4_do_rcv(sk, skb);
1264
1265 if (sk_filter(sk, skb, 0))
1266 goto discard;
1267
1268 /*
1269 * socket locking is here for SMP purposes as backlog rcv
1270 * is currently called with bh processing disabled.
1271 */
1272
1273 /* Do Stevens' IPV6_PKTOPTIONS.
1274
1275 Yes, guys, it is the only place in our code, where we
1276 may make it not affecting IPv4.
1277 The rest of code is protocol independent,
1278 and I do not like idea to uglify IPv4.
1279
1280 Actually, all the idea behind IPV6_PKTOPTIONS
1281 looks not very well thought. For now we latch
1282 options, received in the last packet, enqueued
1283 by tcp. Feel free to propose better solution.
1284 --ANK (980728)
1285 */
1286 if (np->rxopt.all)
1287 opt_skb = skb_clone(skb, GFP_ATOMIC);
1288
1289 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1290 TCP_CHECK_TIMER(sk);
1291 if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
1292 goto reset;
1293 TCP_CHECK_TIMER(sk);
1294 if (opt_skb)
1295 goto ipv6_pktoptions;
1296 return 0;
1297 }
1298
1299 if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
1300 goto csum_err;
1301
1302 if (sk->sk_state == TCP_LISTEN) {
1303 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1304 if (!nsk)
1305 goto discard;
1306
1307 /*
1308 * Queue it on the new socket if the new socket is active,
1309 * otherwise we just shortcircuit this and continue with
1310 * the new socket..
1311 */
1312 if(nsk != sk) {
1313 if (tcp_child_process(sk, nsk, skb))
1314 goto reset;
1315 if (opt_skb)
1316 __kfree_skb(opt_skb);
1317 return 0;
1318 }
1319 }
1320
1321 TCP_CHECK_TIMER(sk);
1322 if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
1323 goto reset;
1324 TCP_CHECK_TIMER(sk);
1325 if (opt_skb)
1326 goto ipv6_pktoptions;
1327 return 0;
1328
1329reset:
1330 tcp_v6_send_reset(skb);
1331discard:
1332 if (opt_skb)
1333 __kfree_skb(opt_skb);
1334 kfree_skb(skb);
1335 return 0;
1336csum_err:
1337 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1338 goto discard;
1339
1340
1341ipv6_pktoptions:
1342 /* Do you ask, what is it?
1343
1344 1. skb was enqueued by tcp.
1345 2. skb is added to tail of read queue, rather than out of order.
1346 3. socket is not in passive state.
1347 4. Finally, it really contains options, which user wants to receive.
1348 */
1349 tp = tcp_sk(sk);
1350 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1351 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001352 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001353 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001354 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
1356 if (ipv6_opt_accepted(sk, opt_skb)) {
1357 skb_set_owner_r(opt_skb, sk);
1358 opt_skb = xchg(&np->pktoptions, opt_skb);
1359 } else {
1360 __kfree_skb(opt_skb);
1361 opt_skb = xchg(&np->pktoptions, NULL);
1362 }
1363 }
1364
1365 if (opt_skb)
1366 kfree_skb(opt_skb);
1367 return 0;
1368}
1369
1370static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
1371{
1372 struct sk_buff *skb = *pskb;
1373 struct tcphdr *th;
1374 struct sock *sk;
1375 int ret;
1376
1377 if (skb->pkt_type != PACKET_HOST)
1378 goto discard_it;
1379
1380 /*
1381 * Count it even if it's bad.
1382 */
1383 TCP_INC_STATS_BH(TCP_MIB_INSEGS);
1384
1385 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1386 goto discard_it;
1387
1388 th = skb->h.th;
1389
1390 if (th->doff < sizeof(struct tcphdr)/4)
1391 goto bad_packet;
1392 if (!pskb_may_pull(skb, th->doff*4))
1393 goto discard_it;
1394
1395 if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
Herbert Xufb286bb2005-11-10 13:01:24 -08001396 tcp_v6_checksum_init(skb)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 goto bad_packet;
1398
1399 th = skb->h.th;
1400 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1401 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1402 skb->len - th->doff*4);
1403 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1404 TCP_SKB_CB(skb)->when = 0;
1405 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
1406 TCP_SKB_CB(skb)->sacked = 0;
1407
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001408 sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source,
1409 &skb->nh.ipv6h->daddr, ntohs(th->dest),
1410 inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
1412 if (!sk)
1413 goto no_tcp_socket;
1414
1415process:
1416 if (sk->sk_state == TCP_TIME_WAIT)
1417 goto do_time_wait;
1418
1419 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1420 goto discard_and_relse;
1421
1422 if (sk_filter(sk, skb, 0))
1423 goto discard_and_relse;
1424
1425 skb->dev = NULL;
1426
1427 bh_lock_sock(sk);
1428 ret = 0;
1429 if (!sock_owned_by_user(sk)) {
1430 if (!tcp_prequeue(sk, skb))
1431 ret = tcp_v6_do_rcv(sk, skb);
1432 } else
1433 sk_add_backlog(sk, skb);
1434 bh_unlock_sock(sk);
1435
1436 sock_put(sk);
1437 return ret ? -1 : 0;
1438
1439no_tcp_socket:
1440 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1441 goto discard_it;
1442
1443 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1444bad_packet:
1445 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1446 } else {
1447 tcp_v6_send_reset(skb);
1448 }
1449
1450discard_it:
1451
1452 /*
1453 * Discard frame
1454 */
1455
1456 kfree_skb(skb);
1457 return 0;
1458
1459discard_and_relse:
1460 sock_put(sk);
1461 goto discard_it;
1462
1463do_time_wait:
1464 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001465 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 goto discard_it;
1467 }
1468
1469 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1470 TCP_INC_STATS_BH(TCP_MIB_INERRS);
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001471 inet_twsk_put((struct inet_timewait_sock *)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 goto discard_it;
1473 }
1474
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001475 switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
1476 skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 case TCP_TW_SYN:
1478 {
1479 struct sock *sk2;
1480
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001481 sk2 = inet6_lookup_listener(&tcp_hashinfo,
1482 &skb->nh.ipv6h->daddr,
1483 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001485 struct inet_timewait_sock *tw = inet_twsk(sk);
1486 inet_twsk_deschedule(tw, &tcp_death_row);
1487 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 sk = sk2;
1489 goto process;
1490 }
1491 /* Fall through to ACK */
1492 }
1493 case TCP_TW_ACK:
1494 tcp_v6_timewait_ack(sk, skb);
1495 break;
1496 case TCP_TW_RST:
1497 goto no_tcp_socket;
1498 case TCP_TW_SUCCESS:;
1499 }
1500 goto discard_it;
1501}
1502
1503static int tcp_v6_rebuild_header(struct sock *sk)
1504{
1505 int err;
1506 struct dst_entry *dst;
1507 struct ipv6_pinfo *np = inet6_sk(sk);
1508
1509 dst = __sk_dst_check(sk, np->dst_cookie);
1510
1511 if (dst == NULL) {
1512 struct inet_sock *inet = inet_sk(sk);
1513 struct in6_addr *final_p = NULL, final;
1514 struct flowi fl;
1515
1516 memset(&fl, 0, sizeof(fl));
1517 fl.proto = IPPROTO_TCP;
1518 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1519 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
1520 fl.fl6_flowlabel = np->flow_label;
1521 fl.oif = sk->sk_bound_dev_if;
1522 fl.fl_ip_dport = inet->dport;
1523 fl.fl_ip_sport = inet->sport;
1524
1525 if (np->opt && np->opt->srcrt) {
1526 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
1527 ipv6_addr_copy(&final, &fl.fl6_dst);
1528 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1529 final_p = &final;
1530 }
1531
1532 err = ip6_dst_lookup(sk, &dst, &fl);
1533 if (err) {
1534 sk->sk_route_caps = 0;
1535 return err;
1536 }
1537 if (final_p)
1538 ipv6_addr_copy(&fl.fl6_dst, final_p);
1539
1540 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
1541 sk->sk_err_soft = -err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 return err;
1543 }
1544
1545 ip6_dst_store(sk, dst, NULL);
1546 sk->sk_route_caps = dst->dev->features &
1547 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
1548 }
1549
1550 return 0;
1551}
1552
1553static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
1554{
1555 struct sock *sk = skb->sk;
1556 struct inet_sock *inet = inet_sk(sk);
1557 struct ipv6_pinfo *np = inet6_sk(sk);
1558 struct flowi fl;
1559 struct dst_entry *dst;
1560 struct in6_addr *final_p = NULL, final;
1561
1562 memset(&fl, 0, sizeof(fl));
1563 fl.proto = IPPROTO_TCP;
1564 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1565 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
1566 fl.fl6_flowlabel = np->flow_label;
1567 IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
1568 fl.oif = sk->sk_bound_dev_if;
1569 fl.fl_ip_sport = inet->sport;
1570 fl.fl_ip_dport = inet->dport;
1571
1572 if (np->opt && np->opt->srcrt) {
1573 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
1574 ipv6_addr_copy(&final, &fl.fl6_dst);
1575 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1576 final_p = &final;
1577 }
1578
1579 dst = __sk_dst_check(sk, np->dst_cookie);
1580
1581 if (dst == NULL) {
1582 int err = ip6_dst_lookup(sk, &dst, &fl);
1583
1584 if (err) {
1585 sk->sk_err_soft = -err;
1586 return err;
1587 }
1588
1589 if (final_p)
1590 ipv6_addr_copy(&fl.fl6_dst, final_p);
1591
1592 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
1593 sk->sk_route_caps = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 return err;
1595 }
1596
1597 ip6_dst_store(sk, dst, NULL);
1598 sk->sk_route_caps = dst->dev->features &
1599 ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
1600 }
1601
1602 skb->dst = dst_clone(dst);
1603
1604 /* Restore final destination back after routing done */
1605 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
1606
1607 return ip6_xmit(sk, skb, &fl, np->opt, 0);
1608}
1609
1610static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
1611{
1612 struct ipv6_pinfo *np = inet6_sk(sk);
1613 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
1614
1615 sin6->sin6_family = AF_INET6;
1616 ipv6_addr_copy(&sin6->sin6_addr, &np->daddr);
1617 sin6->sin6_port = inet_sk(sk)->dport;
1618 /* We do not store received flowlabel for TCP */
1619 sin6->sin6_flowinfo = 0;
1620 sin6->sin6_scope_id = 0;
1621 if (sk->sk_bound_dev_if &&
1622 ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
1623 sin6->sin6_scope_id = sk->sk_bound_dev_if;
1624}
1625
1626static int tcp_v6_remember_stamp(struct sock *sk)
1627{
1628 /* Alas, not yet... */
1629 return 0;
1630}
1631
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001632static struct inet_connection_sock_af_ops ipv6_specific = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 .queue_xmit = tcp_v6_xmit,
1634 .send_check = tcp_v6_send_check,
1635 .rebuild_header = tcp_v6_rebuild_header,
1636 .conn_request = tcp_v6_conn_request,
1637 .syn_recv_sock = tcp_v6_syn_recv_sock,
1638 .remember_stamp = tcp_v6_remember_stamp,
1639 .net_header_len = sizeof(struct ipv6hdr),
1640
1641 .setsockopt = ipv6_setsockopt,
1642 .getsockopt = ipv6_getsockopt,
1643 .addr2sockaddr = v6_addr2sockaddr,
1644 .sockaddr_len = sizeof(struct sockaddr_in6)
1645};
1646
1647/*
1648 * TCP over IPv4 via INET6 API
1649 */
1650
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001651static struct inet_connection_sock_af_ops ipv6_mapped = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 .queue_xmit = ip_queue_xmit,
1653 .send_check = tcp_v4_send_check,
Arnaldo Carvalho de Melo32519f12005-08-09 19:50:02 -07001654 .rebuild_header = inet_sk_rebuild_header,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 .conn_request = tcp_v6_conn_request,
1656 .syn_recv_sock = tcp_v6_syn_recv_sock,
1657 .remember_stamp = tcp_v4_remember_stamp,
1658 .net_header_len = sizeof(struct iphdr),
1659
1660 .setsockopt = ipv6_setsockopt,
1661 .getsockopt = ipv6_getsockopt,
1662 .addr2sockaddr = v6_addr2sockaddr,
1663 .sockaddr_len = sizeof(struct sockaddr_in6)
1664};
1665
1666
1667
1668/* NOTE: A lot of things set to zero explicitly by call to
1669 * sk_alloc() so need not be done here.
1670 */
1671static int tcp_v6_init_sock(struct sock *sk)
1672{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001673 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 struct tcp_sock *tp = tcp_sk(sk);
1675
1676 skb_queue_head_init(&tp->out_of_order_queue);
1677 tcp_init_xmit_timers(sk);
1678 tcp_prequeue_init(tp);
1679
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001680 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 tp->mdev = TCP_TIMEOUT_INIT;
1682
1683 /* So many TCP implementations out there (incorrectly) count the
1684 * initial SYN frame in their delayed-ACK and congestion control
1685 * algorithms that we must have the following bandaid to talk
1686 * efficiently to them. -DaveM
1687 */
1688 tp->snd_cwnd = 2;
1689
1690 /* See draft-stevens-tcpca-spec-01 for discussion of the
1691 * initialization of these values.
1692 */
1693 tp->snd_ssthresh = 0x7fffffff;
1694 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001695 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 tp->reordering = sysctl_tcp_reordering;
1698
1699 sk->sk_state = TCP_CLOSE;
1700
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001701 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001702 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 sk->sk_write_space = sk_stream_write_space;
1704 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1705
1706 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1707 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1708
1709 atomic_inc(&tcp_sockets_allocated);
1710
1711 return 0;
1712}
1713
1714static int tcp_v6_destroy_sock(struct sock *sk)
1715{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 tcp_v4_destroy_sock(sk);
1717 return inet6_destroy_sock(sk);
1718}
1719
1720/* Proc filesystem TCPv6 sock list dumping. */
1721static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001722 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001725 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1726 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 if (ttd < 0)
1729 ttd = 0;
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 seq_printf(seq,
1732 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1733 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1734 i,
1735 src->s6_addr32[0], src->s6_addr32[1],
1736 src->s6_addr32[2], src->s6_addr32[3],
1737 ntohs(inet_sk(sk)->sport),
1738 dest->s6_addr32[0], dest->s6_addr32[1],
1739 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001740 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 TCP_SYN_RECV,
1742 0,0, /* could print option size, but that is af dependent. */
1743 1, /* timers active (only the expire timer) */
1744 jiffies_to_clock_t(ttd),
1745 req->retrans,
1746 uid,
1747 0, /* non standard timer */
1748 0, /* open_requests have no inode */
1749 0, req);
1750}
1751
1752static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1753{
1754 struct in6_addr *dest, *src;
1755 __u16 destp, srcp;
1756 int timer_active;
1757 unsigned long timer_expires;
1758 struct inet_sock *inet = inet_sk(sp);
1759 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001760 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 struct ipv6_pinfo *np = inet6_sk(sp);
1762
1763 dest = &np->daddr;
1764 src = &np->rcv_saddr;
1765 destp = ntohs(inet->dport);
1766 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001767
1768 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001770 timer_expires = icsk->icsk_timeout;
1771 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001773 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 } else if (timer_pending(&sp->sk_timer)) {
1775 timer_active = 2;
1776 timer_expires = sp->sk_timer.expires;
1777 } else {
1778 timer_active = 0;
1779 timer_expires = jiffies;
1780 }
1781
1782 seq_printf(seq,
1783 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1784 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
1785 i,
1786 src->s6_addr32[0], src->s6_addr32[1],
1787 src->s6_addr32[2], src->s6_addr32[3], srcp,
1788 dest->s6_addr32[0], dest->s6_addr32[1],
1789 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1790 sp->sk_state,
1791 tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
1792 timer_active,
1793 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001794 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001796 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 sock_i_ino(sp),
1798 atomic_read(&sp->sk_refcnt), sp,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001799 icsk->icsk_rto,
1800 icsk->icsk_ack.ato,
1801 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
1803 );
1804}
1805
1806static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001807 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808{
1809 struct in6_addr *dest, *src;
1810 __u16 destp, srcp;
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001811 struct tcp6_timewait_sock *tcp6tw = tcp6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 int ttd = tw->tw_ttd - jiffies;
1813
1814 if (ttd < 0)
1815 ttd = 0;
1816
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001817 dest = &tcp6tw->tw_v6_daddr;
1818 src = &tcp6tw->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 destp = ntohs(tw->tw_dport);
1820 srcp = ntohs(tw->tw_sport);
1821
1822 seq_printf(seq,
1823 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1824 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1825 i,
1826 src->s6_addr32[0], src->s6_addr32[1],
1827 src->s6_addr32[2], src->s6_addr32[3], srcp,
1828 dest->s6_addr32[0], dest->s6_addr32[1],
1829 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1830 tw->tw_substate, 0, 0,
1831 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1832 atomic_read(&tw->tw_refcnt), tw);
1833}
1834
1835#ifdef CONFIG_PROC_FS
1836static int tcp6_seq_show(struct seq_file *seq, void *v)
1837{
1838 struct tcp_iter_state *st;
1839
1840 if (v == SEQ_START_TOKEN) {
1841 seq_puts(seq,
1842 " sl "
1843 "local_address "
1844 "remote_address "
1845 "st tx_queue rx_queue tr tm->when retrnsmt"
1846 " uid timeout inode\n");
1847 goto out;
1848 }
1849 st = seq->private;
1850
1851 switch (st->state) {
1852 case TCP_SEQ_STATE_LISTENING:
1853 case TCP_SEQ_STATE_ESTABLISHED:
1854 get_tcp6_sock(seq, v, st->num);
1855 break;
1856 case TCP_SEQ_STATE_OPENREQ:
1857 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
1858 break;
1859 case TCP_SEQ_STATE_TIME_WAIT:
1860 get_timewait6_sock(seq, v, st->num);
1861 break;
1862 }
1863out:
1864 return 0;
1865}
1866
1867static struct file_operations tcp6_seq_fops;
1868static struct tcp_seq_afinfo tcp6_seq_afinfo = {
1869 .owner = THIS_MODULE,
1870 .name = "tcp6",
1871 .family = AF_INET6,
1872 .seq_show = tcp6_seq_show,
1873 .seq_fops = &tcp6_seq_fops,
1874};
1875
1876int __init tcp6_proc_init(void)
1877{
1878 return tcp_proc_register(&tcp6_seq_afinfo);
1879}
1880
1881void tcp6_proc_exit(void)
1882{
1883 tcp_proc_unregister(&tcp6_seq_afinfo);
1884}
1885#endif
1886
1887struct proto tcpv6_prot = {
1888 .name = "TCPv6",
1889 .owner = THIS_MODULE,
1890 .close = tcp_close,
1891 .connect = tcp_v6_connect,
1892 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001893 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 .ioctl = tcp_ioctl,
1895 .init = tcp_v6_init_sock,
1896 .destroy = tcp_v6_destroy_sock,
1897 .shutdown = tcp_shutdown,
1898 .setsockopt = tcp_setsockopt,
1899 .getsockopt = tcp_getsockopt,
1900 .sendmsg = tcp_sendmsg,
1901 .recvmsg = tcp_recvmsg,
1902 .backlog_rcv = tcp_v6_do_rcv,
1903 .hash = tcp_v6_hash,
1904 .unhash = tcp_unhash,
1905 .get_port = tcp_v6_get_port,
1906 .enter_memory_pressure = tcp_enter_memory_pressure,
1907 .sockets_allocated = &tcp_sockets_allocated,
1908 .memory_allocated = &tcp_memory_allocated,
1909 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07001910 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 .sysctl_mem = sysctl_tcp_mem,
1912 .sysctl_wmem = sysctl_tcp_wmem,
1913 .sysctl_rmem = sysctl_tcp_rmem,
1914 .max_header = MAX_TCP_HEADER,
1915 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001916 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001917 .rsk_prot = &tcp6_request_sock_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918};
1919
1920static struct inet6_protocol tcpv6_protocol = {
1921 .handler = tcp_v6_rcv,
1922 .err_handler = tcp_v6_err,
1923 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1924};
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926static struct inet_protosw tcpv6_protosw = {
1927 .type = SOCK_STREAM,
1928 .protocol = IPPROTO_TCP,
1929 .prot = &tcpv6_prot,
1930 .ops = &inet6_stream_ops,
1931 .capability = -1,
1932 .no_check = 0,
1933 .flags = INET_PROTOSW_PERMANENT,
1934};
1935
1936void __init tcpv6_init(void)
1937{
1938 /* register inet6 protocol */
1939 if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
1940 printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
1941 inet6_register_protosw(&tcpv6_protosw);
1942}