blob: cbdb78487915de967bcf99e91d104e145c98f9fb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * TCP over IPv6
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09003 * Linux INET6 implementation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * Authors:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09006 * Pedro Roque <roque@di.fc.ul.pt>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $
9 *
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +090010 * Based on:
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 * linux/net/ipv4/tcp.c
12 * linux/net/ipv4/tcp_input.c
13 * linux/net/ipv4/tcp_output.c
14 *
15 * Fixes:
16 * Hideaki YOSHIFUJI : sin6_scope_id support
17 * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
18 * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
19 * a single port at the same time.
20 * YOSHIFUJI Hideaki @USAGI: convert /proc/net/tcp6 to seq_file.
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version
25 * 2 of the License, or (at your option) any later version.
26 */
27
28#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/errno.h>
30#include <linux/types.h>
31#include <linux/socket.h>
32#include <linux/sockios.h>
33#include <linux/net.h>
34#include <linux/jiffies.h>
35#include <linux/in.h>
36#include <linux/in6.h>
37#include <linux/netdevice.h>
38#include <linux/init.h>
39#include <linux/jhash.h>
40#include <linux/ipsec.h>
41#include <linux/times.h>
42
43#include <linux/ipv6.h>
44#include <linux/icmpv6.h>
45#include <linux/random.h>
46
47#include <net/tcp.h>
48#include <net/ndisc.h>
Arnaldo Carvalho de Melo5324a042005-08-12 09:26:18 -030049#include <net/inet6_hashtables.h>
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -080050#include <net/inet6_connection_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <net/ipv6.h>
52#include <net/transp_v6.h>
53#include <net/addrconf.h>
54#include <net/ip6_route.h>
55#include <net/ip6_checksum.h>
56#include <net/inet_ecn.h>
57#include <net/protocol.h>
58#include <net/xfrm.h>
59#include <net/addrconf.h>
60#include <net/snmp.h>
61#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080062#include <net/timewait_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64#include <asm/uaccess.h>
65
66#include <linux/proc_fs.h>
67#include <linux/seq_file.h>
68
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080069#include <linux/crypto.h>
70#include <linux/scatterlist.h>
71
David Woodhouseae0f7d52006-01-11 15:53:04 -080072/* Socket used for sending RSTs and ACKs */
73static struct socket *tcp6_socket;
74
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080075static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -070076static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +090077static void tcp_v6_send_check(struct sock *sk, int len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 struct sk_buff *skb);
79
80static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080082static struct inet_connection_sock_af_ops ipv6_mapped;
83static struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080084#ifdef CONFIG_TCP_MD5SIG
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080085static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
86static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
David S. Millera9286302006-11-14 19:53:22 -080087#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
90{
Arnaldo Carvalho de Melo971af182005-12-13 23:14:47 -080091 return inet_csk_get_port(&tcp_hashinfo, sk, snum,
92 inet6_csk_bind_conflict);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static void tcp_v6_hash(struct sock *sk)
96{
97 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080098 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 tcp_prot.hash(sk);
100 return;
101 }
102 local_bh_disable();
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -0800103 __inet6_hash(&tcp_hashinfo, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 local_bh_enable();
105 }
106}
107
Al Viro868c86b2006-11-14 21:35:48 -0800108static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900109 struct in6_addr *saddr,
110 struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800111 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
113 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
114}
115
Gerrit Renkera94f7232006-11-10 14:06:49 -0800116static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700118 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
119 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700120 tcp_hdr(skb)->dest,
121 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900124static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 int addr_len)
126{
127 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900128 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800129 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct ipv6_pinfo *np = inet6_sk(sk);
131 struct tcp_sock *tp = tcp_sk(sk);
132 struct in6_addr *saddr = NULL, *final_p = NULL, final;
133 struct flowi fl;
134 struct dst_entry *dst;
135 int addr_type;
136 int err;
137
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900138 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 return -EINVAL;
140
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900141 if (usin->sin6_family != AF_INET6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 return(-EAFNOSUPPORT);
143
144 memset(&fl, 0, sizeof(fl));
145
146 if (np->sndflow) {
147 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
148 IP6_ECN_flow_init(fl.fl6_flowlabel);
149 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
150 struct ip6_flowlabel *flowlabel;
151 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
152 if (flowlabel == NULL)
153 return -EINVAL;
154 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
155 fl6_sock_release(flowlabel);
156 }
157 }
158
159 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900160 * connect() to INADDR_ANY means loopback (BSD'ism).
161 */
162
163 if(ipv6_addr_any(&usin->sin6_addr))
164 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 addr_type = ipv6_addr_type(&usin->sin6_addr);
167
168 if(addr_type & IPV6_ADDR_MULTICAST)
169 return -ENETUNREACH;
170
171 if (addr_type&IPV6_ADDR_LINKLOCAL) {
172 if (addr_len >= sizeof(struct sockaddr_in6) &&
173 usin->sin6_scope_id) {
174 /* If interface is set while binding, indices
175 * must coincide.
176 */
177 if (sk->sk_bound_dev_if &&
178 sk->sk_bound_dev_if != usin->sin6_scope_id)
179 return -EINVAL;
180
181 sk->sk_bound_dev_if = usin->sin6_scope_id;
182 }
183
184 /* Connect to link-local address requires an interface */
185 if (!sk->sk_bound_dev_if)
186 return -EINVAL;
187 }
188
189 if (tp->rx_opt.ts_recent_stamp &&
190 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
191 tp->rx_opt.ts_recent = 0;
192 tp->rx_opt.ts_recent_stamp = 0;
193 tp->write_seq = 0;
194 }
195
196 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
197 np->flow_label = fl.fl6_flowlabel;
198
199 /*
200 * TCP over IPv4
201 */
202
203 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800204 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 struct sockaddr_in sin;
206
207 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
208
209 if (__ipv6_only_sock(sk))
210 return -ENETUNREACH;
211
212 sin.sin_family = AF_INET;
213 sin.sin_port = usin->sin6_port;
214 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
215
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800216 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800218#ifdef CONFIG_TCP_MD5SIG
219 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
220#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
223
224 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800225 icsk->icsk_ext_hdr_len = exthdrlen;
226 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800228#ifdef CONFIG_TCP_MD5SIG
229 tp->af_specific = &tcp_sock_ipv6_specific;
230#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 goto failure;
232 } else {
233 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
234 inet->saddr);
235 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
236 inet->rcv_saddr);
237 }
238
239 return err;
240 }
241
242 if (!ipv6_addr_any(&np->rcv_saddr))
243 saddr = &np->rcv_saddr;
244
245 fl.proto = IPPROTO_TCP;
246 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
247 ipv6_addr_copy(&fl.fl6_src,
248 (saddr ? saddr : &np->saddr));
249 fl.oif = sk->sk_bound_dev_if;
250 fl.fl_ip_dport = usin->sin6_port;
251 fl.fl_ip_sport = inet->sport;
252
253 if (np->opt && np->opt->srcrt) {
254 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
255 ipv6_addr_copy(&final, &fl.fl6_dst);
256 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
257 final_p = &final;
258 }
259
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700260 security_sk_classify_flow(sk, &fl);
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 err = ip6_dst_lookup(sk, &dst, &fl);
263 if (err)
264 goto failure;
265 if (final_p)
266 ipv6_addr_copy(&fl.fl6_dst, final_p);
267
David S. Miller14e50e52007-05-24 18:17:54 -0700268 if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
269 if (err == -EREMOTE)
270 err = ip6_dst_blackhole(sk, &dst, &fl);
271 if (err < 0)
272 goto failure;
273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 if (saddr == NULL) {
276 saddr = &fl.fl6_src;
277 ipv6_addr_copy(&np->rcv_saddr, saddr);
278 }
279
280 /* set the source address */
281 ipv6_addr_copy(&np->saddr, saddr);
282 inet->rcv_saddr = LOOPBACK4_IPV6;
283
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700284 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700285 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800287 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800289 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
290 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
293
294 inet->dport = usin->sin6_port;
295
296 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800297 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 if (err)
299 goto late_failure;
300
301 if (!tp->write_seq)
302 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
303 np->daddr.s6_addr32,
304 inet->sport,
305 inet->dport);
306
307 err = tcp_connect(sk);
308 if (err)
309 goto late_failure;
310
311 return 0;
312
313late_failure:
314 tcp_set_state(sk, TCP_CLOSE);
315 __sk_dst_reset(sk);
316failure:
317 inet->dport = 0;
318 sk->sk_route_caps = 0;
319 return err;
320}
321
322static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Al Viro04ce6902006-11-08 00:21:01 -0800323 int type, int code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
325 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300326 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 struct ipv6_pinfo *np;
328 struct sock *sk;
329 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900330 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 __u32 seq;
332
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300333 sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
334 th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
336 if (sk == NULL) {
337 ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
338 return;
339 }
340
341 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700342 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 return;
344 }
345
346 bh_lock_sock(sk);
347 if (sock_owned_by_user(sk))
348 NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
349
350 if (sk->sk_state == TCP_CLOSE)
351 goto out;
352
353 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900354 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 if (sk->sk_state != TCP_LISTEN &&
356 !between(seq, tp->snd_una, tp->snd_nxt)) {
357 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
358 goto out;
359 }
360
361 np = inet6_sk(sk);
362
363 if (type == ICMPV6_PKT_TOOBIG) {
364 struct dst_entry *dst = NULL;
365
366 if (sock_owned_by_user(sk))
367 goto out;
368 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
369 goto out;
370
371 /* icmp should have updated the destination cache entry */
372 dst = __sk_dst_check(sk, np->dst_cookie);
373
374 if (dst == NULL) {
375 struct inet_sock *inet = inet_sk(sk);
376 struct flowi fl;
377
378 /* BUGGG_FUTURE: Again, it is not clear how
379 to handle rthdr case. Ignore this complexity
380 for now.
381 */
382 memset(&fl, 0, sizeof(fl));
383 fl.proto = IPPROTO_TCP;
384 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
385 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
386 fl.oif = sk->sk_bound_dev_if;
387 fl.fl_ip_dport = inet->dport;
388 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700389 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
391 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
392 sk->sk_err_soft = -err;
393 goto out;
394 }
395
396 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
397 sk->sk_err_soft = -err;
398 goto out;
399 }
400
401 } else
402 dst_hold(dst);
403
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800404 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 tcp_sync_mss(sk, dst_mtu(dst));
406 tcp_simple_retransmit(sk);
407 } /* else let the usual retransmit timer handle it */
408 dst_release(dst);
409 goto out;
410 }
411
412 icmpv6_err_convert(type, code, &err);
413
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700414 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700416 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 case TCP_LISTEN:
418 if (sock_owned_by_user(sk))
419 goto out;
420
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800421 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
422 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 if (!req)
424 goto out;
425
426 /* ICMPs are not backlogged, hence we cannot get
427 * an established socket here.
428 */
429 BUG_TRAP(req->sk == NULL);
430
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700431 if (seq != tcp_rsk(req)->snt_isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
433 goto out;
434 }
435
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700436 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 goto out;
438
439 case TCP_SYN_SENT:
440 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900441 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 sk->sk_err = err;
444 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
445
446 tcp_done(sk);
447 } else
448 sk->sk_err_soft = err;
449 goto out;
450 }
451
452 if (!sock_owned_by_user(sk) && np->recverr) {
453 sk->sk_err = err;
454 sk->sk_error_report(sk);
455 } else
456 sk->sk_err_soft = err;
457
458out:
459 bh_unlock_sock(sk);
460 sock_put(sk);
461}
462
463
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700464static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 struct dst_entry *dst)
466{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800467 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 struct ipv6_pinfo *np = inet6_sk(sk);
469 struct sk_buff * skb;
470 struct ipv6_txoptions *opt = NULL;
471 struct in6_addr * final_p = NULL, final;
472 struct flowi fl;
473 int err = -1;
474
475 memset(&fl, 0, sizeof(fl));
476 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700477 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
478 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700480 fl.oif = treq->iif;
481 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700483 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
485 if (dst == NULL) {
486 opt = np->opt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (opt && opt->srcrt) {
488 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
489 ipv6_addr_copy(&final, &fl.fl6_dst);
490 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
491 final_p = &final;
492 }
493
494 err = ip6_dst_lookup(sk, &dst, &fl);
495 if (err)
496 goto done;
497 if (final_p)
498 ipv6_addr_copy(&fl.fl6_dst, final_p);
499 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
500 goto done;
501 }
502
503 skb = tcp_make_synack(sk, dst, req);
504 if (skb) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700505 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 th->check = tcp_v6_check(th, skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700508 &treq->loc_addr, &treq->rmt_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 csum_partial((char *)th, skb->len, skb->csum));
510
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700511 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 err = ip6_xmit(sk, skb, &fl, opt, 0);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200513 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 }
515
516done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900517 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800519 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 return err;
521}
522
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700523static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800525 if (inet6_rsk(req)->pktopts)
526 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800529#ifdef CONFIG_TCP_MD5SIG
530static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
531 struct in6_addr *addr)
532{
533 struct tcp_sock *tp = tcp_sk(sk);
534 int i;
535
536 BUG_ON(tp == NULL);
537
538 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
539 return NULL;
540
541 for (i = 0; i < tp->md5sig_info->entries6; i++) {
542 if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, addr) == 0)
543 return (struct tcp_md5sig_key *)&tp->md5sig_info->keys6[i];
544 }
545 return NULL;
546}
547
548static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
549 struct sock *addr_sk)
550{
551 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
552}
553
554static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
555 struct request_sock *req)
556{
557 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
558}
559
560static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
561 char *newkey, u8 newkeylen)
562{
563 /* Add key to the list */
564 struct tcp6_md5sig_key *key;
565 struct tcp_sock *tp = tcp_sk(sk);
566 struct tcp6_md5sig_key *keys;
567
568 key = (struct tcp6_md5sig_key*) tcp_v6_md5_do_lookup(sk, peer);
569 if (key) {
570 /* modify existing entry - just update that one */
571 kfree(key->key);
572 key->key = newkey;
573 key->keylen = newkeylen;
574 } else {
575 /* reallocate new list if current one is full. */
576 if (!tp->md5sig_info) {
577 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
578 if (!tp->md5sig_info) {
579 kfree(newkey);
580 return -ENOMEM;
581 }
David S. Miller3d7dbea2007-06-12 14:36:42 -0700582 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800583 }
584 tcp_alloc_md5sig_pool();
585 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
586 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
587 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
588
589 if (!keys) {
590 tcp_free_md5sig_pool();
591 kfree(newkey);
592 return -ENOMEM;
593 }
594
595 if (tp->md5sig_info->entries6)
596 memmove(keys, tp->md5sig_info->keys6,
597 (sizeof (tp->md5sig_info->keys6[0]) *
598 tp->md5sig_info->entries6));
599
600 kfree(tp->md5sig_info->keys6);
601 tp->md5sig_info->keys6 = keys;
602 tp->md5sig_info->alloced6++;
603 }
604
605 ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
606 peer);
607 tp->md5sig_info->keys6[tp->md5sig_info->entries6].key = newkey;
608 tp->md5sig_info->keys6[tp->md5sig_info->entries6].keylen = newkeylen;
609
610 tp->md5sig_info->entries6++;
611 }
612 return 0;
613}
614
615static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
616 u8 *newkey, __u8 newkeylen)
617{
618 return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr,
619 newkey, newkeylen);
620}
621
622static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
623{
624 struct tcp_sock *tp = tcp_sk(sk);
625 int i;
626
627 for (i = 0; i < tp->md5sig_info->entries6; i++) {
628 if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, peer) == 0) {
629 /* Free the key */
630 kfree(tp->md5sig_info->keys6[i].key);
631 tp->md5sig_info->entries6--;
632
633 if (tp->md5sig_info->entries6 == 0) {
634 kfree(tp->md5sig_info->keys6);
635 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700636 tp->md5sig_info->alloced6 = 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800637
638 tcp_free_md5sig_pool();
639
640 return 0;
641 } else {
642 /* shrink the database */
643 if (tp->md5sig_info->entries6 != i)
644 memmove(&tp->md5sig_info->keys6[i],
645 &tp->md5sig_info->keys6[i+1],
646 (tp->md5sig_info->entries6 - i)
647 * sizeof (tp->md5sig_info->keys6[0]));
648 }
649 }
650 }
651 return -ENOENT;
652}
653
654static void tcp_v6_clear_md5_list (struct sock *sk)
655{
656 struct tcp_sock *tp = tcp_sk(sk);
657 int i;
658
659 if (tp->md5sig_info->entries6) {
660 for (i = 0; i < tp->md5sig_info->entries6; i++)
661 kfree(tp->md5sig_info->keys6[i].key);
662 tp->md5sig_info->entries6 = 0;
663 tcp_free_md5sig_pool();
664 }
665
666 kfree(tp->md5sig_info->keys6);
667 tp->md5sig_info->keys6 = NULL;
668 tp->md5sig_info->alloced6 = 0;
669
670 if (tp->md5sig_info->entries4) {
671 for (i = 0; i < tp->md5sig_info->entries4; i++)
672 kfree(tp->md5sig_info->keys4[i].key);
673 tp->md5sig_info->entries4 = 0;
674 tcp_free_md5sig_pool();
675 }
676
677 kfree(tp->md5sig_info->keys4);
678 tp->md5sig_info->keys4 = NULL;
679 tp->md5sig_info->alloced4 = 0;
680}
681
682static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
683 int optlen)
684{
685 struct tcp_md5sig cmd;
686 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
687 u8 *newkey;
688
689 if (optlen < sizeof(cmd))
690 return -EINVAL;
691
692 if (copy_from_user(&cmd, optval, sizeof(cmd)))
693 return -EFAULT;
694
695 if (sin6->sin6_family != AF_INET6)
696 return -EINVAL;
697
698 if (!cmd.tcpm_keylen) {
699 if (!tcp_sk(sk)->md5sig_info)
700 return -ENOENT;
701 if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED)
702 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
703 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
704 }
705
706 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
707 return -EINVAL;
708
709 if (!tcp_sk(sk)->md5sig_info) {
710 struct tcp_sock *tp = tcp_sk(sk);
711 struct tcp_md5sig_info *p;
712
713 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
714 if (!p)
715 return -ENOMEM;
716
717 tp->md5sig_info = p;
David S. Miller3d7dbea2007-06-12 14:36:42 -0700718 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800719 }
720
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200721 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800722 if (!newkey)
723 return -ENOMEM;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800724 if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED) {
725 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
726 newkey, cmd.tcpm_keylen);
727 }
728 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
729}
730
731static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
732 struct in6_addr *saddr,
733 struct in6_addr *daddr,
734 struct tcphdr *th, int protocol,
735 int tcplen)
736{
737 struct scatterlist sg[4];
738 __u16 data_len;
739 int block = 0;
Al Viro8e5200f2006-11-20 18:06:37 -0800740 __sum16 cksum;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800741 struct tcp_md5sig_pool *hp;
742 struct tcp6_pseudohdr *bp;
743 struct hash_desc *desc;
744 int err;
745 unsigned int nbytes = 0;
746
747 hp = tcp_get_md5sig_pool();
748 if (!hp) {
749 printk(KERN_WARNING "%s(): hash pool not found...\n", __FUNCTION__);
750 goto clear_hash_noput;
751 }
752 bp = &hp->md5_blk.ip6;
753 desc = &hp->md5_desc;
754
755 /* 1. TCP pseudo-header (RFC2460) */
756 ipv6_addr_copy(&bp->saddr, saddr);
757 ipv6_addr_copy(&bp->daddr, daddr);
758 bp->len = htonl(tcplen);
759 bp->protocol = htonl(protocol);
760
761 sg_set_buf(&sg[block++], bp, sizeof(*bp));
762 nbytes += sizeof(*bp);
763
764 /* 2. TCP header, excluding options */
765 cksum = th->check;
766 th->check = 0;
767 sg_set_buf(&sg[block++], th, sizeof(*th));
768 nbytes += sizeof(*th);
769
770 /* 3. TCP segment data (if any) */
771 data_len = tcplen - (th->doff << 2);
772 if (data_len > 0) {
773 u8 *data = (u8 *)th + (th->doff << 2);
774 sg_set_buf(&sg[block++], data, data_len);
775 nbytes += data_len;
776 }
777
778 /* 4. shared key */
779 sg_set_buf(&sg[block++], key->key, key->keylen);
780 nbytes += key->keylen;
781
782 /* Now store the hash into the packet */
783 err = crypto_hash_init(desc);
784 if (err) {
785 printk(KERN_WARNING "%s(): hash_init failed\n", __FUNCTION__);
786 goto clear_hash;
787 }
788 err = crypto_hash_update(desc, sg, nbytes);
789 if (err) {
790 printk(KERN_WARNING "%s(): hash_update failed\n", __FUNCTION__);
791 goto clear_hash;
792 }
793 err = crypto_hash_final(desc, md5_hash);
794 if (err) {
795 printk(KERN_WARNING "%s(): hash_final failed\n", __FUNCTION__);
796 goto clear_hash;
797 }
798
799 /* Reset header, and free up the crypto */
800 tcp_put_md5sig_pool();
801 th->check = cksum;
802out:
803 return 0;
804clear_hash:
805 tcp_put_md5sig_pool();
806clear_hash_noput:
807 memset(md5_hash, 0, 16);
808 goto out;
809}
810
811static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
812 struct sock *sk,
813 struct dst_entry *dst,
814 struct request_sock *req,
815 struct tcphdr *th, int protocol,
816 int tcplen)
817{
818 struct in6_addr *saddr, *daddr;
819
820 if (sk) {
821 saddr = &inet6_sk(sk)->saddr;
822 daddr = &inet6_sk(sk)->daddr;
823 } else {
824 saddr = &inet6_rsk(req)->loc_addr;
825 daddr = &inet6_rsk(req)->rmt_addr;
826 }
827 return tcp_v6_do_calc_md5_hash(md5_hash, key,
828 saddr, daddr,
829 th, protocol, tcplen);
830}
831
832static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
833{
834 __u8 *hash_location = NULL;
835 struct tcp_md5sig_key *hash_expected;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700836 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700837 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800838 int length = (th->doff << 2) - sizeof (*th);
839 int genhash;
840 u8 *ptr;
841 u8 newhash[16];
842
843 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
844
845 /* If the TCP option is too short, we can short cut */
846 if (length < TCPOLEN_MD5SIG)
847 return hash_expected ? 1 : 0;
848
849 /* parse options */
850 ptr = (u8*)(th + 1);
851 while (length > 0) {
852 int opcode = *ptr++;
853 int opsize;
854
855 switch(opcode) {
856 case TCPOPT_EOL:
857 goto done_opts;
858 case TCPOPT_NOP:
859 length--;
860 continue;
861 default:
862 opsize = *ptr++;
863 if (opsize < 2 || opsize > length)
864 goto done_opts;
865 if (opcode == TCPOPT_MD5SIG) {
866 hash_location = ptr;
867 goto done_opts;
868 }
869 }
870 ptr += opsize - 2;
871 length -= opsize;
872 }
873
874done_opts:
875 /* do we have a hash as expected? */
876 if (!hash_expected) {
877 if (!hash_location)
878 return 0;
879 if (net_ratelimit()) {
880 printk(KERN_INFO "MD5 Hash NOT expected but found "
881 "(" NIP6_FMT ", %u)->"
882 "(" NIP6_FMT ", %u)\n",
883 NIP6(ip6h->saddr), ntohs(th->source),
884 NIP6(ip6h->daddr), ntohs(th->dest));
885 }
886 return 1;
887 }
888
889 if (!hash_location) {
890 if (net_ratelimit()) {
891 printk(KERN_INFO "MD5 Hash expected but NOT found "
892 "(" NIP6_FMT ", %u)->"
893 "(" NIP6_FMT ", %u)\n",
894 NIP6(ip6h->saddr), ntohs(th->source),
895 NIP6(ip6h->daddr), ntohs(th->dest));
896 }
897 return 1;
898 }
899
900 /* check the signature */
901 genhash = tcp_v6_do_calc_md5_hash(newhash,
902 hash_expected,
903 &ip6h->saddr, &ip6h->daddr,
904 th, sk->sk_protocol,
905 skb->len);
906 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
907 if (net_ratelimit()) {
908 printk(KERN_INFO "MD5 Hash %s for "
909 "(" NIP6_FMT ", %u)->"
910 "(" NIP6_FMT ", %u)\n",
911 genhash ? "failed" : "mismatch",
912 NIP6(ip6h->saddr), ntohs(th->source),
913 NIP6(ip6h->daddr), ntohs(th->dest));
914 }
915 return 1;
916 }
917 return 0;
918}
919#endif
920
David S. Miller9ec75fe2006-11-09 16:26:09 -0800921static struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700923 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700925 .send_ack = tcp_v6_reqsk_send_ack,
926 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 .send_reset = tcp_v6_send_reset
928};
929
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800930#ifdef CONFIG_TCP_MD5SIG
Andrew Mortonb6332e62006-11-30 19:16:28 -0800931static struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800932 .md5_lookup = tcp_v6_reqsk_md5_lookup,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800933};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800934#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800935
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800936static struct timewait_sock_ops tcp6_timewait_sock_ops = {
937 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
938 .twsk_unique = tcp_twsk_unique,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800939 .twsk_destructor= tcp_twsk_destructor,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800940};
941
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800942static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
944 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700945 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
Patrick McHardy84fa7932006-08-29 16:44:56 -0700947 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700949 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800950 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 } else {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900952 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
953 csum_partial((char *)th, th->doff<<2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 skb->csum));
955 }
956}
957
Herbert Xua430a432006-07-08 13:34:56 -0700958static int tcp_v6_gso_send_check(struct sk_buff *skb)
959{
960 struct ipv6hdr *ipv6h;
961 struct tcphdr *th;
962
963 if (!pskb_may_pull(skb, sizeof(*th)))
964 return -EINVAL;
965
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700966 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700967 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700968
969 th->check = 0;
970 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
971 IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700972 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800973 skb->csum_offset = offsetof(struct tcphdr, check);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700974 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xua430a432006-07-08 13:34:56 -0700975 return 0;
976}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800978static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700980 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 struct sk_buff *buff;
982 struct flowi fl;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800983 int tot_len = sizeof(*th);
984#ifdef CONFIG_TCP_MD5SIG
985 struct tcp_md5sig_key *key;
986#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 if (th->rst)
989 return;
990
991 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900992 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800994#ifdef CONFIG_TCP_MD5SIG
995 if (sk)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700996 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800997 else
998 key = NULL;
999
1000 if (key)
1001 tot_len += TCPOLEN_MD5SIG_ALIGNED;
1002#endif
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 /*
1005 * We need to grab some memory, and put together an RST,
1006 * and then put it into the queue to be sent.
1007 */
1008
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001009 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 GFP_ATOMIC);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001011 if (buff == NULL)
1012 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001014 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001016 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
1018 /* Swap the send and the receive. */
1019 memset(t1, 0, sizeof(*t1));
1020 t1->dest = th->source;
1021 t1->source = th->dest;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001022 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 t1->rst = 1;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 if(th->ack) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001026 t1->seq = th->ack_seq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 } else {
1028 t1->ack = 1;
1029 t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
1030 + skb->len - (th->doff<<2));
1031 }
1032
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001033#ifdef CONFIG_TCP_MD5SIG
1034 if (key) {
Al Viro8e5200f2006-11-20 18:06:37 -08001035 __be32 *opt = (__be32*)(t1 + 1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001036 opt[0] = htonl((TCPOPT_NOP << 24) |
1037 (TCPOPT_NOP << 16) |
1038 (TCPOPT_MD5SIG << 8) |
1039 TCPOLEN_MD5SIG);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001040 tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key,
1041 &ipv6_hdr(skb)->daddr,
1042 &ipv6_hdr(skb)->saddr,
1043 t1, IPPROTO_TCP, tot_len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001044 }
1045#endif
1046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
1048
1049 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001050 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1051 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
1054 sizeof(*t1), IPPROTO_TCP,
1055 buff->csum);
1056
1057 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001058 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 fl.fl_ip_dport = t1->dest;
1060 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001061 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
1063 /* sk = NULL, but it is safe for now. RST socket required. */
1064 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
1065
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001066 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
David Woodhouseae0f7d52006-01-11 15:53:04 -08001067 ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001068 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
1069 TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073
1074 kfree_skb(buff);
1075}
1076
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001077static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
1078 struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001080 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 struct sk_buff *buff;
1082 struct flowi fl;
1083 int tot_len = sizeof(struct tcphdr);
Al Viroe69a4ad2006-11-14 20:56:00 -08001084 __be32 *topt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001085#ifdef CONFIG_TCP_MD5SIG
1086 struct tcp_md5sig_key *key;
1087 struct tcp_md5sig_key tw_key;
1088#endif
1089
1090#ifdef CONFIG_TCP_MD5SIG
1091 if (!tw && skb->sk) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001092 key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001093 } else if (tw && tw->tw_md5_keylen) {
1094 tw_key.key = tw->tw_md5_key;
1095 tw_key.keylen = tw->tw_md5_keylen;
1096 key = &tw_key;
1097 } else {
1098 key = NULL;
1099 }
1100#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
1102 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -07001103 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001104#ifdef CONFIG_TCP_MD5SIG
1105 if (key)
1106 tot_len += TCPOLEN_MD5SIG_ALIGNED;
1107#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
1110 GFP_ATOMIC);
1111 if (buff == NULL)
1112 return;
1113
1114 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
1115
1116 t1 = (struct tcphdr *) skb_push(buff,tot_len);
1117
1118 /* Swap the send and the receive. */
1119 memset(t1, 0, sizeof(*t1));
1120 t1->dest = th->source;
1121 t1->source = th->dest;
1122 t1->doff = tot_len/4;
1123 t1->seq = htonl(seq);
1124 t1->ack_seq = htonl(ack);
1125 t1->ack = 1;
1126 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001127
Al Viroe69a4ad2006-11-14 20:56:00 -08001128 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001131 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1132 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
1133 *topt++ = htonl(tcp_time_stamp);
1134 *topt = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 }
1136
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001137#ifdef CONFIG_TCP_MD5SIG
1138 if (key) {
1139 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1140 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001141 tcp_v6_do_calc_md5_hash((__u8 *)topt, key,
1142 &ipv6_hdr(skb)->daddr,
1143 &ipv6_hdr(skb)->saddr,
1144 t1, IPPROTO_TCP, tot_len);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001145 }
1146#endif
1147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 buff->csum = csum_partial((char *)t1, tot_len, 0);
1149
1150 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001151 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1152 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
1154 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
1155 tot_len, IPPROTO_TCP,
1156 buff->csum);
1157
1158 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001159 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 fl.fl_ip_dport = t1->dest;
1161 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001162 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001165 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
David Woodhouseae0f7d52006-01-11 15:53:04 -08001166 ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001167 TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171
1172 kfree_skb(buff);
1173}
1174
1175static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1176{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001177 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001178 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001180 tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001181 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
1182 tcptw->tw_ts_recent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001184 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185}
1186
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001187static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001189 tcp_v6_send_ack(NULL, 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 -07001190}
1191
1192
1193static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1194{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001195 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001196 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 struct sock *nsk;
1198
1199 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001200 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001201 &ipv6_hdr(skb)->saddr,
1202 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 if (req)
1204 return tcp_check_req(sk, skb, req, prev);
1205
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001206 nsk = __inet6_lookup_established(&tcp_hashinfo, &ipv6_hdr(skb)->saddr,
1207 th->source, &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001208 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
1210 if (nsk) {
1211 if (nsk->sk_state != TCP_TIME_WAIT) {
1212 bh_lock_sock(nsk);
1213 return nsk;
1214 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001215 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 return NULL;
1217 }
1218
1219#if 0 /*def CONFIG_SYN_COOKIES*/
1220 if (!th->rst && !th->syn && th->ack)
1221 sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
1222#endif
1223 return sk;
1224}
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226/* FIXME: this is substantially similar to the ipv4 code.
1227 * Can some kind of merge be done? -- erics
1228 */
1229static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1230{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001231 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 struct ipv6_pinfo *np = inet6_sk(sk);
1233 struct tcp_options_received tmp_opt;
1234 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001235 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 __u32 isn = TCP_SKB_CB(skb)->when;
1237
1238 if (skb->protocol == htons(ETH_P_IP))
1239 return tcp_v4_conn_request(sk, skb);
1240
1241 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001242 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
1244 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001245 * There are no SYN attacks on IPv6, yet...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 */
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001247 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 if (net_ratelimit())
1249 printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001250 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 }
1252
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001253 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 goto drop;
1255
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001256 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 if (req == NULL)
1258 goto drop;
1259
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001260#ifdef CONFIG_TCP_MD5SIG
1261 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1262#endif
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 tcp_clear_options(&tmp_opt);
1265 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1266 tmp_opt.user_mss = tp->rx_opt.user_mss;
1267
1268 tcp_parse_options(skb, &tmp_opt, 0);
1269
1270 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1271 tcp_openreq_init(req, &tmp_opt, skb);
1272
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001273 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001274 ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
1275 ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001276 TCP_ECN_create_request(req, tcp_hdr(skb));
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001277 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 if (ipv6_opt_accepted(sk, skb) ||
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001279 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1280 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 atomic_inc(&skb->users);
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001282 treq->pktopts = skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001284 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286 /* So that link locals have meaning */
1287 if (!sk->sk_bound_dev_if &&
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001288 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001289 treq->iif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001291 if (isn == 0)
Gerrit Renkera94f7232006-11-10 14:06:49 -08001292 isn = tcp_v6_init_sequence(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001294 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001296 security_inet_conn_request(sk, skb, req);
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (tcp_v6_send_synack(sk, req, NULL))
1299 goto drop;
1300
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001301 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 return 0;
1303
1304drop:
1305 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001306 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 return 0; /* don't send reset */
1309}
1310
1311static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001312 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 struct dst_entry *dst)
1314{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001315 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1317 struct tcp6_sock *newtcp6sk;
1318 struct inet_sock *newinet;
1319 struct tcp_sock *newtp;
1320 struct sock *newsk;
1321 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001322#ifdef CONFIG_TCP_MD5SIG
1323 struct tcp_md5sig_key *key;
1324#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326 if (skb->protocol == htons(ETH_P_IP)) {
1327 /*
1328 * v6 mapped
1329 */
1330
1331 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1332
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001333 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 return NULL;
1335
1336 newtcp6sk = (struct tcp6_sock *)newsk;
1337 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1338
1339 newinet = inet_sk(newsk);
1340 newnp = inet6_sk(newsk);
1341 newtp = tcp_sk(newsk);
1342
1343 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1344
1345 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
1346 newinet->daddr);
1347
1348 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
1349 newinet->saddr);
1350
1351 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1352
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001353 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001355#ifdef CONFIG_TCP_MD5SIG
1356 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1357#endif
1358
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 newnp->pktoptions = NULL;
1360 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001361 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001362 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001364 /*
1365 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1366 * here, tcp_create_openreq_child now does this for us, see the comment in
1367 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001371 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 Sync it now.
1373 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001374 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
1376 return newsk;
1377 }
1378
1379 opt = np->opt;
1380
1381 if (sk_acceptq_is_full(sk))
1382 goto out_overflow;
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 if (dst == NULL) {
1385 struct in6_addr *final_p = NULL, final;
1386 struct flowi fl;
1387
1388 memset(&fl, 0, sizeof(fl));
1389 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001390 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 if (opt && opt->srcrt) {
1392 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
1393 ipv6_addr_copy(&final, &fl.fl6_dst);
1394 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1395 final_p = &final;
1396 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001397 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001399 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001401 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 if (ip6_dst_lookup(sk, &dst, &fl))
1404 goto out;
1405
1406 if (final_p)
1407 ipv6_addr_copy(&fl.fl6_dst, final_p);
1408
1409 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
1410 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 newsk = tcp_create_openreq_child(sk, req, skb);
1414 if (newsk == NULL)
1415 goto out;
1416
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001417 /*
1418 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1419 * count here, tcp_create_openreq_child now does this for us, see the
1420 * comment in that function for the gory details. -acme
1421 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Stephen Hemminger59eed272006-08-25 15:55:43 -07001423 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001424 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426 newtcp6sk = (struct tcp6_sock *)newsk;
1427 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1428
1429 newtp = tcp_sk(newsk);
1430 newinet = inet_sk(newsk);
1431 newnp = inet6_sk(newsk);
1432
1433 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1434
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001435 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1436 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1437 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1438 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001440 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
1442 First: no IPv4 options.
1443 */
1444 newinet->opt = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001445 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
1447 /* Clone RX bits */
1448 newnp->rxopt.all = np->rxopt.all;
1449
1450 /* Clone pktoptions received with SYN */
1451 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001452 if (treq->pktopts != NULL) {
1453 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1454 kfree_skb(treq->pktopts);
1455 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 if (newnp->pktoptions)
1457 skb_set_owner_r(newnp->pktoptions, newsk);
1458 }
1459 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001460 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001461 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
1463 /* Clone native IPv6 options from listening socket (if any)
1464
1465 Yes, keeping reference count would be much more clever,
1466 but we make one more one thing there: reattach optmem
1467 to newsk.
1468 */
1469 if (opt) {
1470 newnp->opt = ipv6_dup_options(newsk, opt);
1471 if (opt != np->opt)
1472 sock_kfree_s(sk, opt, opt->tot_len);
1473 }
1474
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001475 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001477 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1478 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
John Heffner5d424d52006-03-20 17:53:41 -08001480 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 tcp_sync_mss(newsk, dst_mtu(dst));
1482 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1483 tcp_initialize_rcv_mss(newsk);
1484
1485 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
1486
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001487#ifdef CONFIG_TCP_MD5SIG
1488 /* Copy over the MD5 key from the original socket */
1489 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1490 /* We're using one, so create a matching key
1491 * on the newsk structure. If we fail to get
1492 * memory, then we end up not copying the key
1493 * across. Shucks.
1494 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001495 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1496 if (newkey != NULL)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001497 tcp_v6_md5_do_add(newsk, &inet6_sk(sk)->daddr,
1498 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001499 }
1500#endif
1501
Arnaldo Carvalho de Melo90b19d32005-12-13 23:15:01 -08001502 __inet6_hash(&tcp_hashinfo, newsk);
Arnaldo Carvalho de Melo2d8c4ce2005-08-09 20:07:13 -07001503 inet_inherit_port(&tcp_hashinfo, sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 return newsk;
1506
1507out_overflow:
1508 NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
1509out:
1510 NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
1511 if (opt && opt != np->opt)
1512 sock_kfree_s(sk, opt, opt->tot_len);
1513 dst_release(dst);
1514 return NULL;
1515}
1516
Al Virob51655b2006-11-14 21:40:42 -08001517static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001519 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001520 if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001521 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001522 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001526
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001527 skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001528 &ipv6_hdr(skb)->saddr,
1529 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001532 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 }
1534 return 0;
1535}
1536
1537/* The socket must have it's spinlock held when we get
1538 * here.
1539 *
1540 * We have a potential double-lock case here, so even when
1541 * doing backlog processing we use the BH locking scheme.
1542 * This is because we cannot sleep with the original spinlock
1543 * held.
1544 */
1545static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1546{
1547 struct ipv6_pinfo *np = inet6_sk(sk);
1548 struct tcp_sock *tp;
1549 struct sk_buff *opt_skb = NULL;
1550
1551 /* Imagine: socket is IPv6. IPv4 packet arrives,
1552 goes to IPv4 receive handler and backlogged.
1553 From backlog it always goes here. Kerboom...
1554 Fortunately, tcp_rcv_established and rcv_established
1555 handle them correctly, but it is not case with
1556 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1557 */
1558
1559 if (skb->protocol == htons(ETH_P_IP))
1560 return tcp_v4_do_rcv(sk, skb);
1561
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001562#ifdef CONFIG_TCP_MD5SIG
1563 if (tcp_v6_inbound_md5_hash (sk, skb))
1564 goto discard;
1565#endif
1566
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001567 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 goto discard;
1569
1570 /*
1571 * socket locking is here for SMP purposes as backlog rcv
1572 * is currently called with bh processing disabled.
1573 */
1574
1575 /* Do Stevens' IPV6_PKTOPTIONS.
1576
1577 Yes, guys, it is the only place in our code, where we
1578 may make it not affecting IPv4.
1579 The rest of code is protocol independent,
1580 and I do not like idea to uglify IPv4.
1581
1582 Actually, all the idea behind IPV6_PKTOPTIONS
1583 looks not very well thought. For now we latch
1584 options, received in the last packet, enqueued
1585 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001586 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 */
1588 if (np->rxopt.all)
1589 opt_skb = skb_clone(skb, GFP_ATOMIC);
1590
1591 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1592 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001593 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 goto reset;
1595 TCP_CHECK_TIMER(sk);
1596 if (opt_skb)
1597 goto ipv6_pktoptions;
1598 return 0;
1599 }
1600
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001601 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 goto csum_err;
1603
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001604 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1606 if (!nsk)
1607 goto discard;
1608
1609 /*
1610 * Queue it on the new socket if the new socket is active,
1611 * otherwise we just shortcircuit this and continue with
1612 * the new socket..
1613 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001614 if(nsk != sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 if (tcp_child_process(sk, nsk, skb))
1616 goto reset;
1617 if (opt_skb)
1618 __kfree_skb(opt_skb);
1619 return 0;
1620 }
1621 }
1622
1623 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001624 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 goto reset;
1626 TCP_CHECK_TIMER(sk);
1627 if (opt_skb)
1628 goto ipv6_pktoptions;
1629 return 0;
1630
1631reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001632 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633discard:
1634 if (opt_skb)
1635 __kfree_skb(opt_skb);
1636 kfree_skb(skb);
1637 return 0;
1638csum_err:
1639 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1640 goto discard;
1641
1642
1643ipv6_pktoptions:
1644 /* Do you ask, what is it?
1645
1646 1. skb was enqueued by tcp.
1647 2. skb is added to tail of read queue, rather than out of order.
1648 3. socket is not in passive state.
1649 4. Finally, it really contains options, which user wants to receive.
1650 */
1651 tp = tcp_sk(sk);
1652 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1653 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001654 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001655 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001656 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001657 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (ipv6_opt_accepted(sk, opt_skb)) {
1659 skb_set_owner_r(opt_skb, sk);
1660 opt_skb = xchg(&np->pktoptions, opt_skb);
1661 } else {
1662 __kfree_skb(opt_skb);
1663 opt_skb = xchg(&np->pktoptions, NULL);
1664 }
1665 }
1666
1667 if (opt_skb)
1668 kfree_skb(opt_skb);
1669 return 0;
1670}
1671
Patrick McHardy951dbc82006-01-06 23:02:34 -08001672static int tcp_v6_rcv(struct sk_buff **pskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673{
1674 struct sk_buff *skb = *pskb;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001675 struct tcphdr *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 struct sock *sk;
1677 int ret;
1678
1679 if (skb->pkt_type != PACKET_HOST)
1680 goto discard_it;
1681
1682 /*
1683 * Count it even if it's bad.
1684 */
1685 TCP_INC_STATS_BH(TCP_MIB_INSEGS);
1686
1687 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1688 goto discard_it;
1689
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001690 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 if (th->doff < sizeof(struct tcphdr)/4)
1693 goto bad_packet;
1694 if (!pskb_may_pull(skb, th->doff*4))
1695 goto discard_it;
1696
Herbert Xu60476372007-04-09 11:59:39 -07001697 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 goto bad_packet;
1699
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001700 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1702 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1703 skb->len - th->doff*4);
1704 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1705 TCP_SKB_CB(skb)->when = 0;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001706 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 TCP_SKB_CB(skb)->sacked = 0;
1708
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001709 sk = __inet6_lookup(&tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source,
1710 &ipv6_hdr(skb)->daddr, ntohs(th->dest),
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001711 inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
1713 if (!sk)
1714 goto no_tcp_socket;
1715
1716process:
1717 if (sk->sk_state == TCP_TIME_WAIT)
1718 goto do_time_wait;
1719
1720 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1721 goto discard_and_relse;
1722
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001723 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 goto discard_and_relse;
1725
1726 skb->dev = NULL;
1727
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001728 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 ret = 0;
1730 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001731#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001732 struct tcp_sock *tp = tcp_sk(sk);
1733 if (tp->ucopy.dma_chan)
1734 ret = tcp_v6_do_rcv(sk, skb);
1735 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001736#endif
1737 {
1738 if (!tcp_prequeue(sk, skb))
1739 ret = tcp_v6_do_rcv(sk, skb);
1740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 } else
1742 sk_add_backlog(sk, skb);
1743 bh_unlock_sock(sk);
1744
1745 sock_put(sk);
1746 return ret ? -1 : 0;
1747
1748no_tcp_socket:
1749 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1750 goto discard_it;
1751
1752 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1753bad_packet:
1754 TCP_INC_STATS_BH(TCP_MIB_INERRS);
1755 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001756 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 }
1758
1759discard_it:
1760
1761 /*
1762 * Discard frame
1763 */
1764
1765 kfree_skb(skb);
1766 return 0;
1767
1768discard_and_relse:
1769 sock_put(sk);
1770 goto discard_it;
1771
1772do_time_wait:
1773 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001774 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 goto discard_it;
1776 }
1777
1778 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1779 TCP_INC_STATS_BH(TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001780 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 goto discard_it;
1782 }
1783
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001784 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 case TCP_TW_SYN:
1786 {
1787 struct sock *sk2;
1788
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001789 sk2 = inet6_lookup_listener(&tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001790 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001791 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001793 struct inet_timewait_sock *tw = inet_twsk(sk);
1794 inet_twsk_deschedule(tw, &tcp_death_row);
1795 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 sk = sk2;
1797 goto process;
1798 }
1799 /* Fall through to ACK */
1800 }
1801 case TCP_TW_ACK:
1802 tcp_v6_timewait_ack(sk, skb);
1803 break;
1804 case TCP_TW_RST:
1805 goto no_tcp_socket;
1806 case TCP_TW_SUCCESS:;
1807 }
1808 goto discard_it;
1809}
1810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811static int tcp_v6_remember_stamp(struct sock *sk)
1812{
1813 /* Alas, not yet... */
1814 return 0;
1815}
1816
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001817static struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001818 .queue_xmit = inet6_csk_xmit,
1819 .send_check = tcp_v6_send_check,
1820 .rebuild_header = inet6_sk_rebuild_header,
1821 .conn_request = tcp_v6_conn_request,
1822 .syn_recv_sock = tcp_v6_syn_recv_sock,
1823 .remember_stamp = tcp_v6_remember_stamp,
1824 .net_header_len = sizeof(struct ipv6hdr),
1825 .setsockopt = ipv6_setsockopt,
1826 .getsockopt = ipv6_getsockopt,
1827 .addr2sockaddr = inet6_csk_addr2sockaddr,
1828 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001829#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001830 .compat_setsockopt = compat_ipv6_setsockopt,
1831 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001832#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833};
1834
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001835#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001836static struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001837 .md5_lookup = tcp_v6_md5_lookup,
1838 .calc_md5_hash = tcp_v6_calc_md5_hash,
1839 .md5_add = tcp_v6_md5_add_func,
1840 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001841};
David S. Millera9286302006-11-14 19:53:22 -08001842#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844/*
1845 * TCP over IPv4 via INET6 API
1846 */
1847
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001848static struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001849 .queue_xmit = ip_queue_xmit,
1850 .send_check = tcp_v4_send_check,
1851 .rebuild_header = inet_sk_rebuild_header,
1852 .conn_request = tcp_v6_conn_request,
1853 .syn_recv_sock = tcp_v6_syn_recv_sock,
1854 .remember_stamp = tcp_v4_remember_stamp,
1855 .net_header_len = sizeof(struct iphdr),
1856 .setsockopt = ipv6_setsockopt,
1857 .getsockopt = ipv6_getsockopt,
1858 .addr2sockaddr = inet6_csk_addr2sockaddr,
1859 .sockaddr_len = sizeof(struct sockaddr_in6),
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001860#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001861 .compat_setsockopt = compat_ipv6_setsockopt,
1862 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001863#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864};
1865
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001866#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001867static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001868 .md5_lookup = tcp_v4_md5_lookup,
1869 .calc_md5_hash = tcp_v4_calc_md5_hash,
1870 .md5_add = tcp_v6_md5_add_func,
1871 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001872};
David S. Millera9286302006-11-14 19:53:22 -08001873#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875/* NOTE: A lot of things set to zero explicitly by call to
1876 * sk_alloc() so need not be done here.
1877 */
1878static int tcp_v6_init_sock(struct sock *sk)
1879{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001880 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 struct tcp_sock *tp = tcp_sk(sk);
1882
1883 skb_queue_head_init(&tp->out_of_order_queue);
1884 tcp_init_xmit_timers(sk);
1885 tcp_prequeue_init(tp);
1886
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001887 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 tp->mdev = TCP_TIMEOUT_INIT;
1889
1890 /* So many TCP implementations out there (incorrectly) count the
1891 * initial SYN frame in their delayed-ACK and congestion control
1892 * algorithms that we must have the following bandaid to talk
1893 * efficiently to them. -DaveM
1894 */
1895 tp->snd_cwnd = 2;
1896
1897 /* See draft-stevens-tcpca-spec-01 for discussion of the
1898 * initialization of these values.
1899 */
1900 tp->snd_ssthresh = 0x7fffffff;
1901 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001902 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904 tp->reordering = sysctl_tcp_reordering;
1905
1906 sk->sk_state = TCP_CLOSE;
1907
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001908 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001909 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001910 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 sk->sk_write_space = sk_stream_write_space;
1912 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1913
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001914#ifdef CONFIG_TCP_MD5SIG
1915 tp->af_specific = &tcp_sock_ipv6_specific;
1916#endif
1917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1919 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1920
1921 atomic_inc(&tcp_sockets_allocated);
1922
1923 return 0;
1924}
1925
1926static int tcp_v6_destroy_sock(struct sock *sk)
1927{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001928#ifdef CONFIG_TCP_MD5SIG
1929 /* Clean up the MD5 key list */
1930 if (tcp_sk(sk)->md5sig_info)
1931 tcp_v6_clear_md5_list(sk);
1932#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 tcp_v4_destroy_sock(sk);
1934 return inet6_destroy_sock(sk);
1935}
1936
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09001937#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001939static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001940 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001943 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1944 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
1946 if (ttd < 0)
1947 ttd = 0;
1948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 seq_printf(seq,
1950 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1951 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1952 i,
1953 src->s6_addr32[0], src->s6_addr32[1],
1954 src->s6_addr32[2], src->s6_addr32[3],
1955 ntohs(inet_sk(sk)->sport),
1956 dest->s6_addr32[0], dest->s6_addr32[1],
1957 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001958 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 TCP_SYN_RECV,
1960 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001961 1, /* timers active (only the expire timer) */
1962 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 req->retrans,
1964 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001965 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 0, /* open_requests have no inode */
1967 0, req);
1968}
1969
1970static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1971{
1972 struct in6_addr *dest, *src;
1973 __u16 destp, srcp;
1974 int timer_active;
1975 unsigned long timer_expires;
1976 struct inet_sock *inet = inet_sk(sp);
1977 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001978 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 struct ipv6_pinfo *np = inet6_sk(sp);
1980
1981 dest = &np->daddr;
1982 src = &np->rcv_saddr;
1983 destp = ntohs(inet->dport);
1984 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001985
1986 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001988 timer_expires = icsk->icsk_timeout;
1989 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001991 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 } else if (timer_pending(&sp->sk_timer)) {
1993 timer_active = 2;
1994 timer_expires = sp->sk_timer.expires;
1995 } else {
1996 timer_active = 0;
1997 timer_expires = jiffies;
1998 }
1999
2000 seq_printf(seq,
2001 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
2002 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n",
2003 i,
2004 src->s6_addr32[0], src->s6_addr32[1],
2005 src->s6_addr32[2], src->s6_addr32[3], srcp,
2006 dest->s6_addr32[0], dest->s6_addr32[1],
2007 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002008 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07002009 tp->write_seq-tp->snd_una,
2010 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 timer_active,
2012 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002013 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03002015 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 sock_i_ino(sp),
2017 atomic_read(&sp->sk_refcnt), sp,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002018 icsk->icsk_rto,
2019 icsk->icsk_ack.ato,
2020 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
2022 );
2023}
2024
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002025static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07002026 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027{
2028 struct in6_addr *dest, *src;
2029 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002030 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 int ttd = tw->tw_ttd - jiffies;
2032
2033 if (ttd < 0)
2034 ttd = 0;
2035
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002036 dest = &tw6->tw_v6_daddr;
2037 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 destp = ntohs(tw->tw_dport);
2039 srcp = ntohs(tw->tw_sport);
2040
2041 seq_printf(seq,
2042 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
2043 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
2044 i,
2045 src->s6_addr32[0], src->s6_addr32[1],
2046 src->s6_addr32[2], src->s6_addr32[3], srcp,
2047 dest->s6_addr32[0], dest->s6_addr32[1],
2048 dest->s6_addr32[2], dest->s6_addr32[3], destp,
2049 tw->tw_substate, 0, 0,
2050 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
2051 atomic_read(&tw->tw_refcnt), tw);
2052}
2053
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054static int tcp6_seq_show(struct seq_file *seq, void *v)
2055{
2056 struct tcp_iter_state *st;
2057
2058 if (v == SEQ_START_TOKEN) {
2059 seq_puts(seq,
2060 " sl "
2061 "local_address "
2062 "remote_address "
2063 "st tx_queue rx_queue tr tm->when retrnsmt"
2064 " uid timeout inode\n");
2065 goto out;
2066 }
2067 st = seq->private;
2068
2069 switch (st->state) {
2070 case TCP_SEQ_STATE_LISTENING:
2071 case TCP_SEQ_STATE_ESTABLISHED:
2072 get_tcp6_sock(seq, v, st->num);
2073 break;
2074 case TCP_SEQ_STATE_OPENREQ:
2075 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
2076 break;
2077 case TCP_SEQ_STATE_TIME_WAIT:
2078 get_timewait6_sock(seq, v, st->num);
2079 break;
2080 }
2081out:
2082 return 0;
2083}
2084
2085static struct file_operations tcp6_seq_fops;
2086static struct tcp_seq_afinfo tcp6_seq_afinfo = {
2087 .owner = THIS_MODULE,
2088 .name = "tcp6",
2089 .family = AF_INET6,
2090 .seq_show = tcp6_seq_show,
2091 .seq_fops = &tcp6_seq_fops,
2092};
2093
2094int __init tcp6_proc_init(void)
2095{
2096 return tcp_proc_register(&tcp6_seq_afinfo);
2097}
2098
2099void tcp6_proc_exit(void)
2100{
2101 tcp_proc_unregister(&tcp6_seq_afinfo);
2102}
2103#endif
2104
2105struct proto tcpv6_prot = {
2106 .name = "TCPv6",
2107 .owner = THIS_MODULE,
2108 .close = tcp_close,
2109 .connect = tcp_v6_connect,
2110 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002111 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 .ioctl = tcp_ioctl,
2113 .init = tcp_v6_init_sock,
2114 .destroy = tcp_v6_destroy_sock,
2115 .shutdown = tcp_shutdown,
2116 .setsockopt = tcp_setsockopt,
2117 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 .recvmsg = tcp_recvmsg,
2119 .backlog_rcv = tcp_v6_do_rcv,
2120 .hash = tcp_v6_hash,
2121 .unhash = tcp_unhash,
2122 .get_port = tcp_v6_get_port,
2123 .enter_memory_pressure = tcp_enter_memory_pressure,
2124 .sockets_allocated = &tcp_sockets_allocated,
2125 .memory_allocated = &tcp_memory_allocated,
2126 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002127 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 .sysctl_mem = sysctl_tcp_mem,
2129 .sysctl_wmem = sysctl_tcp_wmem,
2130 .sysctl_rmem = sysctl_tcp_rmem,
2131 .max_header = MAX_TCP_HEADER,
2132 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002133 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002134 .rsk_prot = &tcp6_request_sock_ops,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002135#ifdef CONFIG_COMPAT
2136 .compat_setsockopt = compat_tcp_setsockopt,
2137 .compat_getsockopt = compat_tcp_getsockopt,
2138#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139};
2140
2141static struct inet6_protocol tcpv6_protocol = {
2142 .handler = tcp_v6_rcv,
2143 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002144 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002145 .gso_segment = tcp_tso_segment,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2147};
2148
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149static struct inet_protosw tcpv6_protosw = {
2150 .type = SOCK_STREAM,
2151 .protocol = IPPROTO_TCP,
2152 .prot = &tcpv6_prot,
2153 .ops = &inet6_stream_ops,
2154 .capability = -1,
2155 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002156 .flags = INET_PROTOSW_PERMANENT |
2157 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158};
2159
2160void __init tcpv6_init(void)
2161{
2162 /* register inet6 protocol */
2163 if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
2164 printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
2165 inet6_register_protosw(&tcpv6_protosw);
David Woodhouseae0f7d52006-01-11 15:53:04 -08002166
Arnaldo Carvalho de Meloc4d93902006-03-20 22:01:03 -08002167 if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW,
2168 IPPROTO_TCP) < 0)
David Woodhouseae0f7d52006-01-11 15:53:04 -08002169 panic("Failed to create the TCPv6 control socket.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170}