blob: 13c65144a00a6a2442d2e351564623a79b41b334 [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 *
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09008 * Based on:
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * linux/net/ipv4/tcp.c
10 * linux/net/ipv4/tcp_input.c
11 * linux/net/ipv4/tcp_output.c
12 *
13 * Fixes:
14 * Hideaki YOSHIFUJI : sin6_scope_id support
15 * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
16 * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind
17 * a single port at the same time.
18 * YOSHIFUJI Hideaki @USAGI: convert /proc/net/tcp6 to seq_file.
19 *
20 * This program is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU General Public License
22 * as published by the Free Software Foundation; either version
23 * 2 of the License, or (at your option) any later version.
24 */
25
26#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/errno.h>
28#include <linux/types.h>
29#include <linux/socket.h>
30#include <linux/sockios.h>
31#include <linux/net.h>
32#include <linux/jiffies.h>
33#include <linux/in.h>
34#include <linux/in6.h>
35#include <linux/netdevice.h>
36#include <linux/init.h>
37#include <linux/jhash.h>
38#include <linux/ipsec.h>
39#include <linux/times.h>
40
41#include <linux/ipv6.h>
42#include <linux/icmpv6.h>
43#include <linux/random.h>
44
45#include <net/tcp.h>
46#include <net/ndisc.h>
Arnaldo Carvalho de Melo5324a042005-08-12 09:26:18 -030047#include <net/inet6_hashtables.h>
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -080048#include <net/inet6_connection_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/ipv6.h>
50#include <net/transp_v6.h>
51#include <net/addrconf.h>
52#include <net/ip6_route.h>
53#include <net/ip6_checksum.h>
54#include <net/inet_ecn.h>
55#include <net/protocol.h>
56#include <net/xfrm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <net/snmp.h>
58#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080059#include <net/timewait_sock.h>
Jeff Garzik18134be2007-10-26 22:53:14 -070060#include <net/netdma.h>
Denis V. Lunev3d58b5f2008-04-03 14:22:32 -070061#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63#include <asm/uaccess.h>
64
65#include <linux/proc_fs.h>
66#include <linux/seq_file.h>
67
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080068#include <linux/crypto.h>
69#include <linux/scatterlist.h>
70
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080071static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
Gui Jianfeng6edafaa2008-08-06 23:50:04 -070072static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
73 struct request_sock *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080077static struct inet_connection_sock_af_ops ipv6_mapped;
78static struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080079#ifdef CONFIG_TCP_MD5SIG
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080080static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
81static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090082#else
83static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
84 struct in6_addr *addr)
85{
86 return NULL;
87}
David S. Millera9286302006-11-14 19:53:22 -080088#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static void tcp_v6_hash(struct sock *sk)
91{
92 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080093 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 tcp_prot.hash(sk);
95 return;
96 }
97 local_bh_disable();
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -080098 __inet6_hash(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 local_bh_enable();
100 }
101}
102
Al Viro868c86b2006-11-14 21:35:48 -0800103static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900104 struct in6_addr *saddr,
105 struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800106 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
108 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
109}
110
Gerrit Renkera94f7232006-11-10 14:06:49 -0800111static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700113 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
114 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700115 tcp_hdr(skb)->dest,
116 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117}
118
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900119static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 int addr_len)
121{
122 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900123 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800124 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 struct ipv6_pinfo *np = inet6_sk(sk);
126 struct tcp_sock *tp = tcp_sk(sk);
127 struct in6_addr *saddr = NULL, *final_p = NULL, final;
128 struct flowi fl;
129 struct dst_entry *dst;
130 int addr_type;
131 int err;
132
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900133 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 return -EINVAL;
135
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900136 if (usin->sin6_family != AF_INET6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 return(-EAFNOSUPPORT);
138
139 memset(&fl, 0, sizeof(fl));
140
141 if (np->sndflow) {
142 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
143 IP6_ECN_flow_init(fl.fl6_flowlabel);
144 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
145 struct ip6_flowlabel *flowlabel;
146 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
147 if (flowlabel == NULL)
148 return -EINVAL;
149 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
150 fl6_sock_release(flowlabel);
151 }
152 }
153
154 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900155 * connect() to INADDR_ANY means loopback (BSD'ism).
156 */
157
158 if(ipv6_addr_any(&usin->sin6_addr))
159 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 addr_type = ipv6_addr_type(&usin->sin6_addr);
162
163 if(addr_type & IPV6_ADDR_MULTICAST)
164 return -ENETUNREACH;
165
166 if (addr_type&IPV6_ADDR_LINKLOCAL) {
167 if (addr_len >= sizeof(struct sockaddr_in6) &&
168 usin->sin6_scope_id) {
169 /* If interface is set while binding, indices
170 * must coincide.
171 */
172 if (sk->sk_bound_dev_if &&
173 sk->sk_bound_dev_if != usin->sin6_scope_id)
174 return -EINVAL;
175
176 sk->sk_bound_dev_if = usin->sin6_scope_id;
177 }
178
179 /* Connect to link-local address requires an interface */
180 if (!sk->sk_bound_dev_if)
181 return -EINVAL;
182 }
183
184 if (tp->rx_opt.ts_recent_stamp &&
185 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
186 tp->rx_opt.ts_recent = 0;
187 tp->rx_opt.ts_recent_stamp = 0;
188 tp->write_seq = 0;
189 }
190
191 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
192 np->flow_label = fl.fl6_flowlabel;
193
194 /*
195 * TCP over IPv4
196 */
197
198 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800199 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 struct sockaddr_in sin;
201
202 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
203
204 if (__ipv6_only_sock(sk))
205 return -ENETUNREACH;
206
207 sin.sin_family = AF_INET;
208 sin.sin_port = usin->sin6_port;
209 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
210
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800211 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800213#ifdef CONFIG_TCP_MD5SIG
214 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
215#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
218
219 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800220 icsk->icsk_ext_hdr_len = exthdrlen;
221 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800223#ifdef CONFIG_TCP_MD5SIG
224 tp->af_specific = &tcp_sock_ipv6_specific;
225#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 goto failure;
227 } else {
228 ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
229 inet->saddr);
230 ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
231 inet->rcv_saddr);
232 }
233
234 return err;
235 }
236
237 if (!ipv6_addr_any(&np->rcv_saddr))
238 saddr = &np->rcv_saddr;
239
240 fl.proto = IPPROTO_TCP;
241 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
242 ipv6_addr_copy(&fl.fl6_src,
243 (saddr ? saddr : &np->saddr));
244 fl.oif = sk->sk_bound_dev_if;
245 fl.fl_ip_dport = usin->sin6_port;
246 fl.fl_ip_sport = inet->sport;
247
248 if (np->opt && np->opt->srcrt) {
249 struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
250 ipv6_addr_copy(&final, &fl.fl6_dst);
251 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
252 final_p = &final;
253 }
254
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700255 security_sk_classify_flow(sk, &fl);
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 err = ip6_dst_lookup(sk, &dst, &fl);
258 if (err)
259 goto failure;
260 if (final_p)
261 ipv6_addr_copy(&fl.fl6_dst, final_p);
262
Herbert Xubb728452007-12-12 18:48:58 -0800263 if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) {
David S. Miller14e50e52007-05-24 18:17:54 -0700264 if (err == -EREMOTE)
265 err = ip6_dst_blackhole(sk, &dst, &fl);
266 if (err < 0)
267 goto failure;
268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270 if (saddr == NULL) {
271 saddr = &fl.fl6_src;
272 ipv6_addr_copy(&np->rcv_saddr, saddr);
273 }
274
275 /* set the source address */
276 ipv6_addr_copy(&np->saddr, saddr);
277 inet->rcv_saddr = LOOPBACK4_IPV6;
278
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700279 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700280 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800282 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800284 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
285 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
288
289 inet->dport = usin->sin6_port;
290
291 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800292 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if (err)
294 goto late_failure;
295
296 if (!tp->write_seq)
297 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
298 np->daddr.s6_addr32,
299 inet->sport,
300 inet->dport);
301
302 err = tcp_connect(sk);
303 if (err)
304 goto late_failure;
305
306 return 0;
307
308late_failure:
309 tcp_set_state(sk, TCP_CLOSE);
310 __sk_dst_reset(sk);
311failure:
312 inet->dport = 0;
313 sk->sk_route_caps = 0;
314 return err;
315}
316
317static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Al Viro04ce6902006-11-08 00:21:01 -0800318 int type, int code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300321 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 struct ipv6_pinfo *np;
323 struct sock *sk;
324 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900325 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 __u32 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700327 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700329 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800330 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700333 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
334 ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 return;
336 }
337
338 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700339 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 return;
341 }
342
343 bh_lock_sock(sk);
344 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700345 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 if (sk->sk_state == TCP_CLOSE)
348 goto out;
349
350 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900351 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (sk->sk_state != TCP_LISTEN &&
353 !between(seq, tp->snd_una, tp->snd_nxt)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700354 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 goto out;
356 }
357
358 np = inet6_sk(sk);
359
360 if (type == ICMPV6_PKT_TOOBIG) {
361 struct dst_entry *dst = NULL;
362
363 if (sock_owned_by_user(sk))
364 goto out;
365 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
366 goto out;
367
368 /* icmp should have updated the destination cache entry */
369 dst = __sk_dst_check(sk, np->dst_cookie);
370
371 if (dst == NULL) {
372 struct inet_sock *inet = inet_sk(sk);
373 struct flowi fl;
374
375 /* BUGGG_FUTURE: Again, it is not clear how
376 to handle rthdr case. Ignore this complexity
377 for now.
378 */
379 memset(&fl, 0, sizeof(fl));
380 fl.proto = IPPROTO_TCP;
381 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
382 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
383 fl.oif = sk->sk_bound_dev_if;
384 fl.fl_ip_dport = inet->dport;
385 fl.fl_ip_sport = inet->sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700386 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
389 sk->sk_err_soft = -err;
390 goto out;
391 }
392
393 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
394 sk->sk_err_soft = -err;
395 goto out;
396 }
397
398 } else
399 dst_hold(dst);
400
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800401 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 tcp_sync_mss(sk, dst_mtu(dst));
403 tcp_simple_retransmit(sk);
404 } /* else let the usual retransmit timer handle it */
405 dst_release(dst);
406 goto out;
407 }
408
409 icmpv6_err_convert(type, code, &err);
410
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700411 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700413 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 case TCP_LISTEN:
415 if (sock_owned_by_user(sk))
416 goto out;
417
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800418 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
419 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 if (!req)
421 goto out;
422
423 /* ICMPs are not backlogged, hence we cannot get
424 * an established socket here.
425 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700426 WARN_ON(req->sk != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700428 if (seq != tcp_rsk(req)->snt_isn) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700429 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 goto out;
431 }
432
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700433 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 goto out;
435
436 case TCP_SYN_SENT:
437 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900438 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 sk->sk_err = err;
441 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
442
443 tcp_done(sk);
444 } else
445 sk->sk_err_soft = err;
446 goto out;
447 }
448
449 if (!sock_owned_by_user(sk) && np->recverr) {
450 sk->sk_err = err;
451 sk->sk_error_report(sk);
452 } else
453 sk->sk_err_soft = err;
454
455out:
456 bh_unlock_sock(sk);
457 sock_put(sk);
458}
459
460
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800461static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800463 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 struct ipv6_pinfo *np = inet6_sk(sk);
465 struct sk_buff * skb;
466 struct ipv6_txoptions *opt = NULL;
467 struct in6_addr * final_p = NULL, final;
468 struct flowi fl;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800469 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 int err = -1;
471
472 memset(&fl, 0, sizeof(fl));
473 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700474 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
475 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700477 fl.oif = treq->iif;
478 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700480 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800482 opt = np->opt;
483 if (opt && opt->srcrt) {
484 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
485 ipv6_addr_copy(&final, &fl.fl6_dst);
486 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
487 final_p = &final;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 }
489
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800490 err = ip6_dst_lookup(sk, &dst, &fl);
491 if (err)
492 goto done;
493 if (final_p)
494 ipv6_addr_copy(&fl.fl6_dst, final_p);
495 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
496 goto done;
497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 skb = tcp_make_synack(sk, dst, req);
499 if (skb) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700500 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 th->check = tcp_v6_check(th, skb->len,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700503 &treq->loc_addr, &treq->rmt_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 csum_partial((char *)th, skb->len, skb->csum));
505
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700506 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 err = ip6_xmit(sk, skb, &fl, opt, 0);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200508 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 }
510
511done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900512 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800514 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 return err;
516}
517
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800518static inline void syn_flood_warning(struct sk_buff *skb)
519{
520#ifdef CONFIG_SYN_COOKIES
521 if (sysctl_tcp_syncookies)
522 printk(KERN_INFO
523 "TCPv6: Possible SYN flooding on port %d. "
524 "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
525 else
526#endif
527 printk(KERN_INFO
528 "TCPv6: Possible SYN flooding on port %d. "
529 "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
530}
531
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700532static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800534 if (inet6_rsk(req)->pktopts)
535 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536}
537
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800538#ifdef CONFIG_TCP_MD5SIG
539static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
540 struct in6_addr *addr)
541{
542 struct tcp_sock *tp = tcp_sk(sk);
543 int i;
544
545 BUG_ON(tp == NULL);
546
547 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
548 return NULL;
549
550 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900551 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
David S. Millerf8ab18d2007-09-28 15:18:35 -0700552 return &tp->md5sig_info->keys6[i].base;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800553 }
554 return NULL;
555}
556
557static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
558 struct sock *addr_sk)
559{
560 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
561}
562
563static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
564 struct request_sock *req)
565{
566 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
567}
568
569static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
570 char *newkey, u8 newkeylen)
571{
572 /* Add key to the list */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700573 struct tcp_md5sig_key *key;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800574 struct tcp_sock *tp = tcp_sk(sk);
575 struct tcp6_md5sig_key *keys;
576
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700577 key = tcp_v6_md5_do_lookup(sk, peer);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800578 if (key) {
579 /* modify existing entry - just update that one */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700580 kfree(key->key);
581 key->key = newkey;
582 key->keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800583 } else {
584 /* reallocate new list if current one is full. */
585 if (!tp->md5sig_info) {
586 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
587 if (!tp->md5sig_info) {
588 kfree(newkey);
589 return -ENOMEM;
590 }
David S. Miller3d7dbea2007-06-12 14:36:42 -0700591 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800592 }
YOSHIFUJI Hideakiaacbe8c2007-11-20 17:30:56 -0800593 if (tcp_alloc_md5sig_pool() == NULL) {
594 kfree(newkey);
595 return -ENOMEM;
596 }
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800597 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
598 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
599 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
600
601 if (!keys) {
602 tcp_free_md5sig_pool();
603 kfree(newkey);
604 return -ENOMEM;
605 }
606
607 if (tp->md5sig_info->entries6)
608 memmove(keys, tp->md5sig_info->keys6,
609 (sizeof (tp->md5sig_info->keys6[0]) *
610 tp->md5sig_info->entries6));
611
612 kfree(tp->md5sig_info->keys6);
613 tp->md5sig_info->keys6 = keys;
614 tp->md5sig_info->alloced6++;
615 }
616
617 ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
618 peer);
David S. Millerf8ab18d2007-09-28 15:18:35 -0700619 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
620 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800621
622 tp->md5sig_info->entries6++;
623 }
624 return 0;
625}
626
627static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
628 u8 *newkey, __u8 newkeylen)
629{
630 return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr,
631 newkey, newkeylen);
632}
633
634static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
635{
636 struct tcp_sock *tp = tcp_sk(sk);
637 int i;
638
639 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900640 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800641 /* Free the key */
David S. Millerf8ab18d2007-09-28 15:18:35 -0700642 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800643 tp->md5sig_info->entries6--;
644
645 if (tp->md5sig_info->entries6 == 0) {
646 kfree(tp->md5sig_info->keys6);
647 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700648 tp->md5sig_info->alloced6 = 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800649 } else {
650 /* shrink the database */
651 if (tp->md5sig_info->entries6 != i)
652 memmove(&tp->md5sig_info->keys6[i],
653 &tp->md5sig_info->keys6[i+1],
654 (tp->md5sig_info->entries6 - i)
655 * sizeof (tp->md5sig_info->keys6[0]));
656 }
YOSHIFUJI Hideaki77adefd2007-11-20 17:31:23 -0800657 tcp_free_md5sig_pool();
658 return 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800659 }
660 }
661 return -ENOENT;
662}
663
664static void tcp_v6_clear_md5_list (struct sock *sk)
665{
666 struct tcp_sock *tp = tcp_sk(sk);
667 int i;
668
669 if (tp->md5sig_info->entries6) {
670 for (i = 0; i < tp->md5sig_info->entries6; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700671 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800672 tp->md5sig_info->entries6 = 0;
673 tcp_free_md5sig_pool();
674 }
675
676 kfree(tp->md5sig_info->keys6);
677 tp->md5sig_info->keys6 = NULL;
678 tp->md5sig_info->alloced6 = 0;
679
680 if (tp->md5sig_info->entries4) {
681 for (i = 0; i < tp->md5sig_info->entries4; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700682 kfree(tp->md5sig_info->keys4[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800683 tp->md5sig_info->entries4 = 0;
684 tcp_free_md5sig_pool();
685 }
686
687 kfree(tp->md5sig_info->keys4);
688 tp->md5sig_info->keys4 = NULL;
689 tp->md5sig_info->alloced4 = 0;
690}
691
692static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
693 int optlen)
694{
695 struct tcp_md5sig cmd;
696 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
697 u8 *newkey;
698
699 if (optlen < sizeof(cmd))
700 return -EINVAL;
701
702 if (copy_from_user(&cmd, optval, sizeof(cmd)))
703 return -EFAULT;
704
705 if (sin6->sin6_family != AF_INET6)
706 return -EINVAL;
707
708 if (!cmd.tcpm_keylen) {
709 if (!tcp_sk(sk)->md5sig_info)
710 return -ENOENT;
Brian Haleye773e4f2007-08-24 23:16:08 -0700711 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800712 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
713 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
714 }
715
716 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
717 return -EINVAL;
718
719 if (!tcp_sk(sk)->md5sig_info) {
720 struct tcp_sock *tp = tcp_sk(sk);
721 struct tcp_md5sig_info *p;
722
723 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
724 if (!p)
725 return -ENOMEM;
726
727 tp->md5sig_info = p;
David S. Miller3d7dbea2007-06-12 14:36:42 -0700728 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800729 }
730
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200731 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800732 if (!newkey)
733 return -ENOMEM;
Brian Haleye773e4f2007-08-24 23:16:08 -0700734 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800735 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
736 newkey, cmd.tcpm_keylen);
737 }
738 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
739}
740
Adam Langley49a72df2008-07-19 00:01:42 -0700741static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
742 struct in6_addr *daddr,
743 struct in6_addr *saddr, int nbytes)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800744{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800745 struct tcp6_pseudohdr *bp;
Adam Langley49a72df2008-07-19 00:01:42 -0700746 struct scatterlist sg;
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900747
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800748 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800749 /* 1. TCP pseudo-header (RFC2460) */
750 ipv6_addr_copy(&bp->saddr, saddr);
751 ipv6_addr_copy(&bp->daddr, daddr);
Adam Langley49a72df2008-07-19 00:01:42 -0700752 bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley00b13042008-07-31 21:36:07 -0700753 bp->len = cpu_to_be32(nbytes);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800754
Adam Langley49a72df2008-07-19 00:01:42 -0700755 sg_init_one(&sg, bp, sizeof(*bp));
756 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
757}
David S. Millerc7da57a2007-10-26 00:41:21 -0700758
Adam Langley49a72df2008-07-19 00:01:42 -0700759static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
760 struct in6_addr *daddr, struct in6_addr *saddr,
761 struct tcphdr *th)
762{
763 struct tcp_md5sig_pool *hp;
764 struct hash_desc *desc;
765
766 hp = tcp_get_md5sig_pool();
767 if (!hp)
768 goto clear_hash_noput;
769 desc = &hp->md5_desc;
770
771 if (crypto_hash_init(desc))
772 goto clear_hash;
773 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
774 goto clear_hash;
775 if (tcp_md5_hash_header(hp, th))
776 goto clear_hash;
777 if (tcp_md5_hash_key(hp, key))
778 goto clear_hash;
779 if (crypto_hash_final(desc, md5_hash))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800780 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800781
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800782 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800783 return 0;
Adam Langley49a72df2008-07-19 00:01:42 -0700784
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800785clear_hash:
786 tcp_put_md5sig_pool();
787clear_hash_noput:
788 memset(md5_hash, 0, 16);
Adam Langley49a72df2008-07-19 00:01:42 -0700789 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800790}
791
Adam Langley49a72df2008-07-19 00:01:42 -0700792static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
793 struct sock *sk, struct request_sock *req,
794 struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800795{
796 struct in6_addr *saddr, *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700797 struct tcp_md5sig_pool *hp;
798 struct hash_desc *desc;
799 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800800
801 if (sk) {
802 saddr = &inet6_sk(sk)->saddr;
803 daddr = &inet6_sk(sk)->daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700804 } else if (req) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800805 saddr = &inet6_rsk(req)->loc_addr;
806 daddr = &inet6_rsk(req)->rmt_addr;
Adam Langley49a72df2008-07-19 00:01:42 -0700807 } else {
808 struct ipv6hdr *ip6h = ipv6_hdr(skb);
809 saddr = &ip6h->saddr;
810 daddr = &ip6h->daddr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800811 }
Adam Langley49a72df2008-07-19 00:01:42 -0700812
813 hp = tcp_get_md5sig_pool();
814 if (!hp)
815 goto clear_hash_noput;
816 desc = &hp->md5_desc;
817
818 if (crypto_hash_init(desc))
819 goto clear_hash;
820
821 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
822 goto clear_hash;
823 if (tcp_md5_hash_header(hp, th))
824 goto clear_hash;
825 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
826 goto clear_hash;
827 if (tcp_md5_hash_key(hp, key))
828 goto clear_hash;
829 if (crypto_hash_final(desc, md5_hash))
830 goto clear_hash;
831
832 tcp_put_md5sig_pool();
833 return 0;
834
835clear_hash:
836 tcp_put_md5sig_pool();
837clear_hash_noput:
838 memset(md5_hash, 0, 16);
839 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800840}
841
842static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
843{
844 __u8 *hash_location = NULL;
845 struct tcp_md5sig_key *hash_expected;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700846 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700847 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800848 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800849 u8 newhash[16];
850
851 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900852 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800853
David S. Miller785957d2008-07-30 03:03:15 -0700854 /* We've parsed the options - do we have a hash? */
855 if (!hash_expected && !hash_location)
856 return 0;
857
858 if (hash_expected && !hash_location) {
859 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800860 return 1;
861 }
862
David S. Miller785957d2008-07-30 03:03:15 -0700863 if (!hash_expected && hash_location) {
864 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800865 return 1;
866 }
867
868 /* check the signature */
Adam Langley49a72df2008-07-19 00:01:42 -0700869 genhash = tcp_v6_md5_hash_skb(newhash,
870 hash_expected,
871 NULL, NULL, skb);
872
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800873 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
874 if (net_ratelimit()) {
875 printk(KERN_INFO "MD5 Hash %s for "
876 "(" NIP6_FMT ", %u)->"
877 "(" NIP6_FMT ", %u)\n",
878 genhash ? "failed" : "mismatch",
879 NIP6(ip6h->saddr), ntohs(th->source),
880 NIP6(ip6h->daddr), ntohs(th->dest));
881 }
882 return 1;
883 }
884 return 0;
885}
886#endif
887
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800888struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700890 .obj_size = sizeof(struct tcp6_request_sock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 .rtx_syn_ack = tcp_v6_send_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700892 .send_ack = tcp_v6_reqsk_send_ack,
893 .destructor = tcp_v6_reqsk_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 .send_reset = tcp_v6_send_reset
895};
896
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800897#ifdef CONFIG_TCP_MD5SIG
Andrew Mortonb6332e62006-11-30 19:16:28 -0800898static struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800899 .md5_lookup = tcp_v6_reqsk_md5_lookup,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800900};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800901#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800902
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800903static struct timewait_sock_ops tcp6_timewait_sock_ops = {
904 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
905 .twsk_unique = tcp_twsk_unique,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800906 .twsk_destructor= tcp_twsk_destructor,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -0800907};
908
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -0800909static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
911 struct ipv6_pinfo *np = inet6_sk(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700912 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Patrick McHardy84fa7932006-08-29 16:44:56 -0700914 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700916 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800917 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 } else {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900919 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
920 csum_partial((char *)th, th->doff<<2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 skb->csum));
922 }
923}
924
Herbert Xua430a432006-07-08 13:34:56 -0700925static int tcp_v6_gso_send_check(struct sk_buff *skb)
926{
927 struct ipv6hdr *ipv6h;
928 struct tcphdr *th;
929
930 if (!pskb_may_pull(skb, sizeof(*th)))
931 return -EINVAL;
932
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700933 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700934 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700935
936 th->check = 0;
937 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
938 IPPROTO_TCP, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700939 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800940 skb->csum_offset = offsetof(struct tcphdr, check);
Patrick McHardy84fa7932006-08-29 16:44:56 -0700941 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xua430a432006-07-08 13:34:56 -0700942 return 0;
943}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700945static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
946 u32 ts, struct tcp_md5sig_key *key, int rst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700948 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 struct sk_buff *buff;
950 struct flowi fl;
Denis V. Lunev2a5b8272008-10-01 02:13:16 -0700951 struct net *net = dev_net(skb->dst->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -0800952 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -0800953 unsigned int tot_len = sizeof(struct tcphdr);
Al Viroe69a4ad2006-11-14 20:56:00 -0800954 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -0700957 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800958#ifdef CONFIG_TCP_MD5SIG
959 if (key)
960 tot_len += TCPOLEN_MD5SIG_ALIGNED;
961#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
964 GFP_ATOMIC);
965 if (buff == NULL)
966 return;
967
968 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
969
Ilpo Järvinen77c676d2008-10-09 14:41:38 -0700970 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972 /* Swap the send and the receive. */
973 memset(t1, 0, sizeof(*t1));
974 t1->dest = th->source;
975 t1->source = th->dest;
Ilpo Järvinen77c676d2008-10-09 14:41:38 -0700976 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 t1->seq = htonl(seq);
978 t1->ack_seq = htonl(ack);
Ilpo Järvinen626e2642008-10-09 14:42:40 -0700979 t1->ack = !rst || !th->ack;
980 t1->rst = rst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800982
Al Viroe69a4ad2006-11-14 20:56:00 -0800983 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800986 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
987 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
988 *topt++ = htonl(tcp_time_stamp);
Ilpo Järvinen53b12572008-10-08 14:36:33 -0700989 *topt++ = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 }
991
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800992#ifdef CONFIG_TCP_MD5SIG
993 if (key) {
994 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
995 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Adam Langley49a72df2008-07-19 00:01:42 -0700996 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
Adam Langley90b7e112008-07-31 20:49:48 -0700997 &ipv6_hdr(skb)->saddr,
998 &ipv6_hdr(skb)->daddr, t1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800999 }
1000#endif
1001
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 buff->csum = csum_partial((char *)t1, tot_len, 0);
1003
1004 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001005 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1006 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
1009 tot_len, IPPROTO_TCP,
1010 buff->csum);
1011
1012 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001013 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 fl.fl_ip_dport = t1->dest;
1015 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001016 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001018 /* Pass a socket to ip6_dst_lookup either it is for RST
1019 * Underlying function will use this to retrieve the network
1020 * namespace
1021 */
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001022 if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001023 if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001024 ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001025 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001026 if (rst)
1027 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
1031
1032 kfree_skb(buff);
1033}
1034
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001035static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
1036{
1037 struct tcphdr *th = tcp_hdr(skb);
1038 u32 seq = 0, ack_seq = 0;
1039#ifdef CONFIG_TCP_MD5SIG
1040 struct tcp_md5sig_key *key;
1041#endif
1042
1043 if (th->rst)
1044 return;
1045
1046 if (!ipv6_unicast_destination(skb))
1047 return;
1048
1049#ifdef CONFIG_TCP_MD5SIG
1050 if (sk)
1051 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
1052 else
1053 key = NULL;
1054#endif
1055
1056 if (th->ack)
1057 seq = ntohl(th->ack_seq);
1058 else
1059 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
1060 (th->doff << 2);
1061
1062 tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1);
1063}
1064
1065static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
1066 struct tcp_md5sig_key *key)
1067{
1068 tcp_v6_send_response(skb, seq, ack, win, ts, key, 0);
1069}
1070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1072{
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001073 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001074 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001076 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001077 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001078 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001080 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081}
1082
Gui Jianfeng6edafaa2008-08-06 23:50:04 -07001083static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
1084 struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001086 tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
Gui Jianfeng6edafaa2008-08-06 23:50:04 -07001087 tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088}
1089
1090
1091static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1092{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001093 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001094 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 struct sock *nsk;
1096
1097 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001098 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001099 &ipv6_hdr(skb)->saddr,
1100 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 if (req)
1102 return tcp_check_req(sk, skb, req, prev);
1103
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001104 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001105 &ipv6_hdr(skb)->saddr, th->source,
1106 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108 if (nsk) {
1109 if (nsk->sk_state != TCP_TIME_WAIT) {
1110 bh_lock_sock(nsk);
1111 return nsk;
1112 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001113 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 return NULL;
1115 }
1116
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001117#ifdef CONFIG_SYN_COOKIES
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 if (!th->rst && !th->syn && th->ack)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001119 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120#endif
1121 return sk;
1122}
1123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124/* FIXME: this is substantially similar to the ipv4 code.
1125 * Can some kind of merge be done? -- erics
1126 */
1127static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1128{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001129 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 struct ipv6_pinfo *np = inet6_sk(sk);
1131 struct tcp_options_received tmp_opt;
1132 struct tcp_sock *tp = tcp_sk(sk);
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001133 struct request_sock *req = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 __u32 isn = TCP_SKB_CB(skb)->when;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001135#ifdef CONFIG_SYN_COOKIES
1136 int want_cookie = 0;
1137#else
1138#define want_cookie 0
1139#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141 if (skb->protocol == htons(ETH_P_IP))
1142 return tcp_v4_conn_request(sk, skb);
1143
1144 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001145 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001147 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 if (net_ratelimit())
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001149 syn_flood_warning(skb);
1150#ifdef CONFIG_SYN_COOKIES
1151 if (sysctl_tcp_syncookies)
1152 want_cookie = 1;
1153 else
1154#endif
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001155 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 }
1157
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001158 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 goto drop;
1160
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001161 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 if (req == NULL)
1163 goto drop;
1164
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001165#ifdef CONFIG_TCP_MD5SIG
1166 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1167#endif
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 tcp_clear_options(&tmp_opt);
1170 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1171 tmp_opt.user_mss = tp->rx_opt.user_mss;
1172
1173 tcp_parse_options(skb, &tmp_opt, 0);
1174
Florian Westphal4dfc2812008-04-10 03:12:40 -07001175 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001176 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1179 tcp_openreq_init(req, &tmp_opt, skb);
1180
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001181 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001182 ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
1183 ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001184 if (!want_cookie)
1185 TCP_ECN_create_request(req, tcp_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001187 if (want_cookie) {
1188 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
Florian Westphal4dfc2812008-04-10 03:12:40 -07001189 req->cookie_ts = tmp_opt.tstamp_ok;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001190 } else if (!isn) {
1191 if (ipv6_opt_accepted(sk, skb) ||
1192 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1193 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1194 atomic_inc(&skb->users);
1195 treq->pktopts = skb;
1196 }
1197 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001199 /* So that link locals have meaning */
1200 if (!sk->sk_bound_dev_if &&
1201 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1202 treq->iif = inet6_iif(skb);
1203
Gerrit Renkera94f7232006-11-10 14:06:49 -08001204 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001207 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001209 security_inet_conn_request(sk, skb, req);
1210
Denis V. Lunevfd80eb92008-02-29 11:43:03 -08001211 if (tcp_v6_send_synack(sk, req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 goto drop;
1213
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001214 if (!want_cookie) {
1215 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1216 return 0;
1217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219drop:
1220 if (req)
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001221 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 return 0; /* don't send reset */
1224}
1225
1226static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001227 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 struct dst_entry *dst)
1229{
Vegard Nossum78d15e82008-09-12 16:17:43 -07001230 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1232 struct tcp6_sock *newtcp6sk;
1233 struct inet_sock *newinet;
1234 struct tcp_sock *newtp;
1235 struct sock *newsk;
1236 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001237#ifdef CONFIG_TCP_MD5SIG
1238 struct tcp_md5sig_key *key;
1239#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241 if (skb->protocol == htons(ETH_P_IP)) {
1242 /*
1243 * v6 mapped
1244 */
1245
1246 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1247
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001248 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 return NULL;
1250
1251 newtcp6sk = (struct tcp6_sock *)newsk;
1252 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1253
1254 newinet = inet_sk(newsk);
1255 newnp = inet6_sk(newsk);
1256 newtp = tcp_sk(newsk);
1257
1258 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1259
1260 ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
1261 newinet->daddr);
1262
1263 ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
1264 newinet->saddr);
1265
1266 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1267
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001268 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001270#ifdef CONFIG_TCP_MD5SIG
1271 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1272#endif
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 newnp->pktoptions = NULL;
1275 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001276 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001277 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001279 /*
1280 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1281 * here, tcp_create_openreq_child now does this for us, see the comment in
1282 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001286 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 Sync it now.
1288 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001289 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291 return newsk;
1292 }
1293
Vegard Nossum78d15e82008-09-12 16:17:43 -07001294 treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 opt = np->opt;
1296
1297 if (sk_acceptq_is_full(sk))
1298 goto out_overflow;
1299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (dst == NULL) {
1301 struct in6_addr *final_p = NULL, final;
1302 struct flowi fl;
1303
1304 memset(&fl, 0, sizeof(fl));
1305 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001306 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (opt && opt->srcrt) {
1308 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
1309 ipv6_addr_copy(&final, &fl.fl6_dst);
1310 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
1311 final_p = &final;
1312 }
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001313 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 fl.oif = sk->sk_bound_dev_if;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001315 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 fl.fl_ip_sport = inet_sk(sk)->sport;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001317 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319 if (ip6_dst_lookup(sk, &dst, &fl))
1320 goto out;
1321
1322 if (final_p)
1323 ipv6_addr_copy(&fl.fl6_dst, final_p);
1324
1325 if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
1326 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 newsk = tcp_create_openreq_child(sk, req, skb);
1330 if (newsk == NULL)
1331 goto out;
1332
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001333 /*
1334 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1335 * count here, tcp_create_openreq_child now does this for us, see the
1336 * comment in that function for the gory details. -acme
1337 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Stephen Hemminger59eed272006-08-25 15:55:43 -07001339 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001340 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
1342 newtcp6sk = (struct tcp6_sock *)newsk;
1343 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1344
1345 newtp = tcp_sk(newsk);
1346 newinet = inet_sk(newsk);
1347 newnp = inet6_sk(newsk);
1348
1349 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1350
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001351 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1352 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1353 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1354 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001356 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 First: no IPv4 options.
1359 */
1360 newinet->opt = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001361 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
1363 /* Clone RX bits */
1364 newnp->rxopt.all = np->rxopt.all;
1365
1366 /* Clone pktoptions received with SYN */
1367 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001368 if (treq->pktopts != NULL) {
1369 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1370 kfree_skb(treq->pktopts);
1371 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (newnp->pktoptions)
1373 skb_set_owner_r(newnp->pktoptions, newsk);
1374 }
1375 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001376 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001377 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379 /* Clone native IPv6 options from listening socket (if any)
1380
1381 Yes, keeping reference count would be much more clever,
1382 but we make one more one thing there: reattach optmem
1383 to newsk.
1384 */
1385 if (opt) {
1386 newnp->opt = ipv6_dup_options(newsk, opt);
1387 if (opt != np->opt)
1388 sock_kfree_s(sk, opt, opt->tot_len);
1389 }
1390
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001391 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001393 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1394 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
John Heffner5d424d52006-03-20 17:53:41 -08001396 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 tcp_sync_mss(newsk, dst_mtu(dst));
1398 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1399 tcp_initialize_rcv_mss(newsk);
1400
1401 newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
1402
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001403#ifdef CONFIG_TCP_MD5SIG
1404 /* Copy over the MD5 key from the original socket */
1405 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1406 /* We're using one, so create a matching key
1407 * on the newsk structure. If we fail to get
1408 * memory, then we end up not copying the key
1409 * across. Shucks.
1410 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001411 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1412 if (newkey != NULL)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001413 tcp_v6_md5_do_add(newsk, &inet6_sk(sk)->daddr,
1414 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001415 }
1416#endif
1417
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001418 __inet6_hash(newsk);
Pavel Emelyanove56d8b82008-04-17 23:17:34 -07001419 __inet_inherit_port(sk, newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
1421 return newsk;
1422
1423out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001424 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425out:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001426 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 if (opt && opt != np->opt)
1428 sock_kfree_s(sk, opt, opt->tot_len);
1429 dst_release(dst);
1430 return NULL;
1431}
1432
Al Virob51655b2006-11-14 21:40:42 -08001433static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001435 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001436 if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001437 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001438 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001442
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001443 skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001444 &ipv6_hdr(skb)->saddr,
1445 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001446
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001448 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 }
1450 return 0;
1451}
1452
1453/* The socket must have it's spinlock held when we get
1454 * here.
1455 *
1456 * We have a potential double-lock case here, so even when
1457 * doing backlog processing we use the BH locking scheme.
1458 * This is because we cannot sleep with the original spinlock
1459 * held.
1460 */
1461static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1462{
1463 struct ipv6_pinfo *np = inet6_sk(sk);
1464 struct tcp_sock *tp;
1465 struct sk_buff *opt_skb = NULL;
1466
1467 /* Imagine: socket is IPv6. IPv4 packet arrives,
1468 goes to IPv4 receive handler and backlogged.
1469 From backlog it always goes here. Kerboom...
1470 Fortunately, tcp_rcv_established and rcv_established
1471 handle them correctly, but it is not case with
1472 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1473 */
1474
1475 if (skb->protocol == htons(ETH_P_IP))
1476 return tcp_v4_do_rcv(sk, skb);
1477
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001478#ifdef CONFIG_TCP_MD5SIG
1479 if (tcp_v6_inbound_md5_hash (sk, skb))
1480 goto discard;
1481#endif
1482
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001483 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 goto discard;
1485
1486 /*
1487 * socket locking is here for SMP purposes as backlog rcv
1488 * is currently called with bh processing disabled.
1489 */
1490
1491 /* Do Stevens' IPV6_PKTOPTIONS.
1492
1493 Yes, guys, it is the only place in our code, where we
1494 may make it not affecting IPv4.
1495 The rest of code is protocol independent,
1496 and I do not like idea to uglify IPv4.
1497
1498 Actually, all the idea behind IPV6_PKTOPTIONS
1499 looks not very well thought. For now we latch
1500 options, received in the last packet, enqueued
1501 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001502 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 */
1504 if (np->rxopt.all)
1505 opt_skb = skb_clone(skb, GFP_ATOMIC);
1506
1507 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1508 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001509 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 goto reset;
1511 TCP_CHECK_TIMER(sk);
1512 if (opt_skb)
1513 goto ipv6_pktoptions;
1514 return 0;
1515 }
1516
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001517 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 goto csum_err;
1519
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001520 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1522 if (!nsk)
1523 goto discard;
1524
1525 /*
1526 * Queue it on the new socket if the new socket is active,
1527 * otherwise we just shortcircuit this and continue with
1528 * the new socket..
1529 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001530 if(nsk != sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 if (tcp_child_process(sk, nsk, skb))
1532 goto reset;
1533 if (opt_skb)
1534 __kfree_skb(opt_skb);
1535 return 0;
1536 }
1537 }
1538
1539 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001540 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 goto reset;
1542 TCP_CHECK_TIMER(sk);
1543 if (opt_skb)
1544 goto ipv6_pktoptions;
1545 return 0;
1546
1547reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001548 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549discard:
1550 if (opt_skb)
1551 __kfree_skb(opt_skb);
1552 kfree_skb(skb);
1553 return 0;
1554csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001555 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 goto discard;
1557
1558
1559ipv6_pktoptions:
1560 /* Do you ask, what is it?
1561
1562 1. skb was enqueued by tcp.
1563 2. skb is added to tail of read queue, rather than out of order.
1564 3. socket is not in passive state.
1565 4. Finally, it really contains options, which user wants to receive.
1566 */
1567 tp = tcp_sk(sk);
1568 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1569 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001570 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001571 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001572 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001573 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 if (ipv6_opt_accepted(sk, opt_skb)) {
1575 skb_set_owner_r(opt_skb, sk);
1576 opt_skb = xchg(&np->pktoptions, opt_skb);
1577 } else {
1578 __kfree_skb(opt_skb);
1579 opt_skb = xchg(&np->pktoptions, NULL);
1580 }
1581 }
1582
1583 if (opt_skb)
1584 kfree_skb(opt_skb);
1585 return 0;
1586}
1587
Herbert Xue5bbef22007-10-15 12:50:28 -07001588static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589{
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001590 struct tcphdr *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 struct sock *sk;
1592 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001593 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
1595 if (skb->pkt_type != PACKET_HOST)
1596 goto discard_it;
1597
1598 /*
1599 * Count it even if it's bad.
1600 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001601 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
1603 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1604 goto discard_it;
1605
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001606 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 if (th->doff < sizeof(struct tcphdr)/4)
1609 goto bad_packet;
1610 if (!pskb_may_pull(skb, th->doff*4))
1611 goto discard_it;
1612
Herbert Xu60476372007-04-09 11:59:39 -07001613 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 goto bad_packet;
1615
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001616 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1618 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1619 skb->len - th->doff*4);
1620 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1621 TCP_SKB_CB(skb)->when = 0;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001622 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 TCP_SKB_CB(skb)->sacked = 0;
1624
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -07001625 sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 if (!sk)
1627 goto no_tcp_socket;
1628
1629process:
1630 if (sk->sk_state == TCP_TIME_WAIT)
1631 goto do_time_wait;
1632
1633 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1634 goto discard_and_relse;
1635
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001636 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 goto discard_and_relse;
1638
1639 skb->dev = NULL;
1640
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001641 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 ret = 0;
1643 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001644#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001645 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001646 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
1647 tp->ucopy.dma_chan = get_softnet_dma();
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001648 if (tp->ucopy.dma_chan)
1649 ret = tcp_v6_do_rcv(sk, skb);
1650 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001651#endif
1652 {
1653 if (!tcp_prequeue(sk, skb))
1654 ret = tcp_v6_do_rcv(sk, skb);
1655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 } else
1657 sk_add_backlog(sk, skb);
1658 bh_unlock_sock(sk);
1659
1660 sock_put(sk);
1661 return ret ? -1 : 0;
1662
1663no_tcp_socket:
1664 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1665 goto discard_it;
1666
1667 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1668bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001669 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001671 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 }
1673
1674discard_it:
1675
1676 /*
1677 * Discard frame
1678 */
1679
1680 kfree_skb(skb);
1681 return 0;
1682
1683discard_and_relse:
1684 sock_put(sk);
1685 goto discard_it;
1686
1687do_time_wait:
1688 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001689 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 goto discard_it;
1691 }
1692
1693 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001694 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001695 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 goto discard_it;
1697 }
1698
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001699 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 case TCP_TW_SYN:
1701 {
1702 struct sock *sk2;
1703
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001704 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001705 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001706 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001708 struct inet_timewait_sock *tw = inet_twsk(sk);
1709 inet_twsk_deschedule(tw, &tcp_death_row);
1710 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 sk = sk2;
1712 goto process;
1713 }
1714 /* Fall through to ACK */
1715 }
1716 case TCP_TW_ACK:
1717 tcp_v6_timewait_ack(sk, skb);
1718 break;
1719 case TCP_TW_RST:
1720 goto no_tcp_socket;
1721 case TCP_TW_SUCCESS:;
1722 }
1723 goto discard_it;
1724}
1725
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726static int tcp_v6_remember_stamp(struct sock *sk)
1727{
1728 /* Alas, not yet... */
1729 return 0;
1730}
1731
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001732static struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001733 .queue_xmit = inet6_csk_xmit,
1734 .send_check = tcp_v6_send_check,
1735 .rebuild_header = inet6_sk_rebuild_header,
1736 .conn_request = tcp_v6_conn_request,
1737 .syn_recv_sock = tcp_v6_syn_recv_sock,
1738 .remember_stamp = tcp_v6_remember_stamp,
1739 .net_header_len = sizeof(struct ipv6hdr),
1740 .setsockopt = ipv6_setsockopt,
1741 .getsockopt = ipv6_getsockopt,
1742 .addr2sockaddr = inet6_csk_addr2sockaddr,
1743 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001744 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001745#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001746 .compat_setsockopt = compat_ipv6_setsockopt,
1747 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001748#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749};
1750
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001751#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001752static struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001753 .md5_lookup = tcp_v6_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001754 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001755 .md5_add = tcp_v6_md5_add_func,
1756 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001757};
David S. Millera9286302006-11-14 19:53:22 -08001758#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001759
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760/*
1761 * TCP over IPv4 via INET6 API
1762 */
1763
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001764static struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001765 .queue_xmit = ip_queue_xmit,
1766 .send_check = tcp_v4_send_check,
1767 .rebuild_header = inet_sk_rebuild_header,
1768 .conn_request = tcp_v6_conn_request,
1769 .syn_recv_sock = tcp_v6_syn_recv_sock,
1770 .remember_stamp = tcp_v4_remember_stamp,
1771 .net_header_len = sizeof(struct iphdr),
1772 .setsockopt = ipv6_setsockopt,
1773 .getsockopt = ipv6_getsockopt,
1774 .addr2sockaddr = inet6_csk_addr2sockaddr,
1775 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001776 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001777#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001778 .compat_setsockopt = compat_ipv6_setsockopt,
1779 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001780#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781};
1782
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001783#ifdef CONFIG_TCP_MD5SIG
David S. Millera9286302006-11-14 19:53:22 -08001784static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001785 .md5_lookup = tcp_v4_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001786 .calc_md5_hash = tcp_v4_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001787 .md5_add = tcp_v6_md5_add_func,
1788 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001789};
David S. Millera9286302006-11-14 19:53:22 -08001790#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792/* NOTE: A lot of things set to zero explicitly by call to
1793 * sk_alloc() so need not be done here.
1794 */
1795static int tcp_v6_init_sock(struct sock *sk)
1796{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001797 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 struct tcp_sock *tp = tcp_sk(sk);
1799
1800 skb_queue_head_init(&tp->out_of_order_queue);
1801 tcp_init_xmit_timers(sk);
1802 tcp_prequeue_init(tp);
1803
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001804 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 tp->mdev = TCP_TIMEOUT_INIT;
1806
1807 /* So many TCP implementations out there (incorrectly) count the
1808 * initial SYN frame in their delayed-ACK and congestion control
1809 * algorithms that we must have the following bandaid to talk
1810 * efficiently to them. -DaveM
1811 */
1812 tp->snd_cwnd = 2;
1813
1814 /* See draft-stevens-tcpca-spec-01 for discussion of the
1815 * initialization of these values.
1816 */
1817 tp->snd_ssthresh = 0x7fffffff;
1818 tp->snd_cwnd_clamp = ~0;
David S. Millerc1b4a7e2005-07-05 15:24:38 -07001819 tp->mss_cache = 536;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
1821 tp->reordering = sysctl_tcp_reordering;
1822
1823 sk->sk_state = TCP_CLOSE;
1824
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001825 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001826 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001827 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 sk->sk_write_space = sk_stream_write_space;
1829 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1830
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001831#ifdef CONFIG_TCP_MD5SIG
1832 tp->af_specific = &tcp_sock_ipv6_specific;
1833#endif
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 sk->sk_sndbuf = sysctl_tcp_wmem[1];
1836 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
1837
1838 atomic_inc(&tcp_sockets_allocated);
1839
1840 return 0;
1841}
1842
Brian Haley7d06b2e2008-06-14 17:04:49 -07001843static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001845#ifdef CONFIG_TCP_MD5SIG
1846 /* Clean up the MD5 key list */
1847 if (tcp_sk(sk)->md5sig_info)
1848 tcp_v6_clear_md5_list(sk);
1849#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07001851 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852}
1853
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09001854#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001856static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001857 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001860 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
1861 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
1863 if (ttd < 0)
1864 ttd = 0;
1865
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 seq_printf(seq,
1867 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1868 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1869 i,
1870 src->s6_addr32[0], src->s6_addr32[1],
1871 src->s6_addr32[2], src->s6_addr32[3],
1872 ntohs(inet_sk(sk)->sport),
1873 dest->s6_addr32[0], dest->s6_addr32[1],
1874 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001875 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 TCP_SYN_RECV,
1877 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001878 1, /* timers active (only the expire timer) */
1879 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 req->retrans,
1881 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001882 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 0, /* open_requests have no inode */
1884 0, req);
1885}
1886
1887static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
1888{
1889 struct in6_addr *dest, *src;
1890 __u16 destp, srcp;
1891 int timer_active;
1892 unsigned long timer_expires;
1893 struct inet_sock *inet = inet_sk(sp);
1894 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001895 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 struct ipv6_pinfo *np = inet6_sk(sp);
1897
1898 dest = &np->daddr;
1899 src = &np->rcv_saddr;
1900 destp = ntohs(inet->dport);
1901 srcp = ntohs(inet->sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001902
1903 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001905 timer_expires = icsk->icsk_timeout;
1906 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001908 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 } else if (timer_pending(&sp->sk_timer)) {
1910 timer_active = 2;
1911 timer_expires = sp->sk_timer.expires;
1912 } else {
1913 timer_active = 0;
1914 timer_expires = jiffies;
1915 }
1916
1917 seq_printf(seq,
1918 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Stephen Hemminger7be87352008-06-27 20:00:19 -07001919 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 i,
1921 src->s6_addr32[0], src->s6_addr32[1],
1922 src->s6_addr32[2], src->s6_addr32[3], srcp,
1923 dest->s6_addr32[0], dest->s6_addr32[1],
1924 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001925 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07001926 tp->write_seq-tp->snd_una,
1927 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 timer_active,
1929 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001930 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001932 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 sock_i_ino(sp),
1934 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07001935 jiffies_to_clock_t(icsk->icsk_rto),
1936 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001937 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
1939 );
1940}
1941
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001942static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c2005-08-09 20:09:30 -07001943 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944{
1945 struct in6_addr *dest, *src;
1946 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001947 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 int ttd = tw->tw_ttd - jiffies;
1949
1950 if (ttd < 0)
1951 ttd = 0;
1952
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08001953 dest = &tw6->tw_v6_daddr;
1954 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 destp = ntohs(tw->tw_dport);
1956 srcp = ntohs(tw->tw_sport);
1957
1958 seq_printf(seq,
1959 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
1960 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
1961 i,
1962 src->s6_addr32[0], src->s6_addr32[1],
1963 src->s6_addr32[2], src->s6_addr32[3], srcp,
1964 dest->s6_addr32[0], dest->s6_addr32[1],
1965 dest->s6_addr32[2], dest->s6_addr32[3], destp,
1966 tw->tw_substate, 0, 0,
1967 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
1968 atomic_read(&tw->tw_refcnt), tw);
1969}
1970
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971static int tcp6_seq_show(struct seq_file *seq, void *v)
1972{
1973 struct tcp_iter_state *st;
1974
1975 if (v == SEQ_START_TOKEN) {
1976 seq_puts(seq,
1977 " sl "
1978 "local_address "
1979 "remote_address "
1980 "st tx_queue rx_queue tr tm->when retrnsmt"
1981 " uid timeout inode\n");
1982 goto out;
1983 }
1984 st = seq->private;
1985
1986 switch (st->state) {
1987 case TCP_SEQ_STATE_LISTENING:
1988 case TCP_SEQ_STATE_ESTABLISHED:
1989 get_tcp6_sock(seq, v, st->num);
1990 break;
1991 case TCP_SEQ_STATE_OPENREQ:
1992 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
1993 break;
1994 case TCP_SEQ_STATE_TIME_WAIT:
1995 get_timewait6_sock(seq, v, st->num);
1996 break;
1997 }
1998out:
1999 return 0;
2000}
2001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 .name = "tcp6",
2004 .family = AF_INET6,
Denis V. Lunev5f4472c2008-04-13 22:13:53 -07002005 .seq_fops = {
2006 .owner = THIS_MODULE,
2007 },
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07002008 .seq_ops = {
2009 .show = tcp6_seq_show,
2010 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011};
2012
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002013int tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002015 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016}
2017
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002018void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002020 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021}
2022#endif
2023
2024struct proto tcpv6_prot = {
2025 .name = "TCPv6",
2026 .owner = THIS_MODULE,
2027 .close = tcp_close,
2028 .connect = tcp_v6_connect,
2029 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002030 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 .ioctl = tcp_ioctl,
2032 .init = tcp_v6_init_sock,
2033 .destroy = tcp_v6_destroy_sock,
2034 .shutdown = tcp_shutdown,
2035 .setsockopt = tcp_setsockopt,
2036 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 .recvmsg = tcp_recvmsg,
2038 .backlog_rcv = tcp_v6_do_rcv,
2039 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08002040 .unhash = inet_unhash,
2041 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 .enter_memory_pressure = tcp_enter_memory_pressure,
2043 .sockets_allocated = &tcp_sockets_allocated,
2044 .memory_allocated = &tcp_memory_allocated,
2045 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002046 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 .sysctl_mem = sysctl_tcp_mem,
2048 .sysctl_wmem = sysctl_tcp_wmem,
2049 .sysctl_rmem = sysctl_tcp_rmem,
2050 .max_header = MAX_TCP_HEADER,
2051 .obj_size = sizeof(struct tcp6_sock),
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002052 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002053 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002054 .h.hashinfo = &tcp_hashinfo,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002055#ifdef CONFIG_COMPAT
2056 .compat_setsockopt = compat_tcp_setsockopt,
2057 .compat_getsockopt = compat_tcp_getsockopt,
2058#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059};
2060
2061static struct inet6_protocol tcpv6_protocol = {
2062 .handler = tcp_v6_rcv,
2063 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002064 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002065 .gso_segment = tcp_tso_segment,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2067};
2068
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069static struct inet_protosw tcpv6_protosw = {
2070 .type = SOCK_STREAM,
2071 .protocol = IPPROTO_TCP,
2072 .prot = &tcpv6_prot,
2073 .ops = &inet6_stream_ops,
2074 .capability = -1,
2075 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002076 .flags = INET_PROTOSW_PERMANENT |
2077 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078};
2079
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002080static int tcpv6_net_init(struct net *net)
2081{
Denis V. Lunev56772422008-04-03 14:28:30 -07002082 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2083 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002084}
2085
2086static void tcpv6_net_exit(struct net *net)
2087{
Denis V. Lunev56772422008-04-03 14:28:30 -07002088 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Daniel Lezcanod3154922008-09-08 13:17:27 -07002089 inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002090}
2091
2092static struct pernet_operations tcpv6_net_ops = {
2093 .init = tcpv6_net_init,
2094 .exit = tcpv6_net_exit,
2095};
2096
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002097int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002099 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002100
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002101 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2102 if (ret)
2103 goto out;
2104
2105 /* register inet6 protocol */
2106 ret = inet6_register_protosw(&tcpv6_protosw);
2107 if (ret)
2108 goto out_tcpv6_protocol;
2109
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002110 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002111 if (ret)
2112 goto out_tcpv6_protosw;
2113out:
2114 return ret;
2115
2116out_tcpv6_protocol:
2117 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2118out_tcpv6_protosw:
2119 inet6_unregister_protosw(&tcpv6_protosw);
2120 goto out;
2121}
2122
Daniel Lezcano09f77092007-12-13 05:34:58 -08002123void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002124{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002125 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002126 inet6_unregister_protosw(&tcpv6_protosw);
2127 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128}