blob: c2ebbe1c5a47a6cb697d73c07d38b1e503708f11 [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
Herbert Xueb4dea52008-12-29 23:04:08 -080026#include <linux/bottom_half.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/errno.h>
29#include <linux/types.h>
30#include <linux/socket.h>
31#include <linux/sockios.h>
32#include <linux/net.h>
33#include <linux/jiffies.h>
34#include <linux/in.h>
35#include <linux/in6.h>
36#include <linux/netdevice.h>
37#include <linux/init.h>
38#include <linux/jhash.h>
39#include <linux/ipsec.h>
40#include <linux/times.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090041#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <linux/ipv6.h>
44#include <linux/icmpv6.h>
45#include <linux/random.h>
46
47#include <net/tcp.h>
48#include <net/ndisc.h>
Arnaldo Carvalho de Melo5324a042005-08-12 09:26:18 -030049#include <net/inet6_hashtables.h>
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -080050#include <net/inet6_connection_sock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <net/ipv6.h>
52#include <net/transp_v6.h>
53#include <net/addrconf.h>
54#include <net/ip6_route.h>
55#include <net/ip6_checksum.h>
56#include <net/inet_ecn.h>
57#include <net/protocol.h>
58#include <net/xfrm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <net/snmp.h>
60#include <net/dsfield.h>
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -080061#include <net/timewait_sock.h>
Jeff Garzik18134be2007-10-26 22:53:14 -070062#include <net/netdma.h>
Denis V. Lunev3d58b5f2008-04-03 14:22:32 -070063#include <net/inet_common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include <asm/uaccess.h>
66
67#include <linux/proc_fs.h>
68#include <linux/seq_file.h>
69
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080070#include <linux/crypto.h>
71#include <linux/scatterlist.h>
72
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -080073static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
Gui Jianfeng6edafaa2008-08-06 23:50:04 -070074static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
75 struct request_sock *req);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
Herbert Xu8ad50d92010-04-11 02:15:54 +000078static void __tcp_v6_send_check(struct sk_buff *skb,
79 struct in6_addr *saddr,
80 struct in6_addr *daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Stephen Hemminger3b401a82009-09-01 19:25:04 +000082static const struct inet_connection_sock_af_ops ipv6_mapped;
83static const struct inet_connection_sock_af_ops ipv6_specific;
David S. Millera9286302006-11-14 19:53:22 -080084#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3de2009-09-01 19:25:03 +000085static const struct tcp_sock_af_ops tcp_sock_ipv6_specific;
86static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +090087#else
88static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
89 struct in6_addr *addr)
90{
91 return NULL;
92}
David S. Millera9286302006-11-14 19:53:22 -080093#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static void tcp_v6_hash(struct sock *sk)
96{
97 if (sk->sk_state != TCP_CLOSE) {
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -080098 if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 tcp_prot.hash(sk);
100 return;
101 }
102 local_bh_disable();
Eric Dumazet9327f702009-12-04 03:46:54 +0000103 __inet6_hash(sk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 local_bh_enable();
105 }
106}
107
Herbert Xu684f2172009-01-08 10:41:23 -0800108static __inline__ __sum16 tcp_v6_check(int len,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900109 struct in6_addr *saddr,
110 struct in6_addr *daddr,
Al Viro868c86b2006-11-14 21:35:48 -0800111 __wsum base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
113 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
114}
115
Gerrit Renkera94f7232006-11-10 14:06:49 -0800116static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700118 return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
119 ipv6_hdr(skb)->saddr.s6_addr32,
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700120 tcp_hdr(skb)->dest,
121 tcp_hdr(skb)->source);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122}
123
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900124static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 int addr_len)
126{
127 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900128 struct inet_sock *inet = inet_sk(sk);
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800129 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct ipv6_pinfo *np = inet6_sk(sk);
131 struct tcp_sock *tp = tcp_sk(sk);
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000132 struct in6_addr *saddr = NULL, *final_p, final;
David S. Miller493f3772010-12-02 12:14:29 -0800133 struct rt6_info *rt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct flowi fl;
135 struct dst_entry *dst;
136 int addr_type;
137 int err;
138
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900139 if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 return -EINVAL;
141
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900142 if (usin->sin6_family != AF_INET6)
Eric Dumazeta02cec22010-09-22 20:43:57 +0000143 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145 memset(&fl, 0, sizeof(fl));
146
147 if (np->sndflow) {
148 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
149 IP6_ECN_flow_init(fl.fl6_flowlabel);
150 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
151 struct ip6_flowlabel *flowlabel;
152 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
153 if (flowlabel == NULL)
154 return -EINVAL;
155 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
156 fl6_sock_release(flowlabel);
157 }
158 }
159
160 /*
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900161 * connect() to INADDR_ANY means loopback (BSD'ism).
162 */
163
164 if(ipv6_addr_any(&usin->sin6_addr))
165 usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 addr_type = ipv6_addr_type(&usin->sin6_addr);
168
169 if(addr_type & IPV6_ADDR_MULTICAST)
170 return -ENETUNREACH;
171
172 if (addr_type&IPV6_ADDR_LINKLOCAL) {
173 if (addr_len >= sizeof(struct sockaddr_in6) &&
174 usin->sin6_scope_id) {
175 /* If interface is set while binding, indices
176 * must coincide.
177 */
178 if (sk->sk_bound_dev_if &&
179 sk->sk_bound_dev_if != usin->sin6_scope_id)
180 return -EINVAL;
181
182 sk->sk_bound_dev_if = usin->sin6_scope_id;
183 }
184
185 /* Connect to link-local address requires an interface */
186 if (!sk->sk_bound_dev_if)
187 return -EINVAL;
188 }
189
190 if (tp->rx_opt.ts_recent_stamp &&
191 !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
192 tp->rx_opt.ts_recent = 0;
193 tp->rx_opt.ts_recent_stamp = 0;
194 tp->write_seq = 0;
195 }
196
197 ipv6_addr_copy(&np->daddr, &usin->sin6_addr);
198 np->flow_label = fl.fl6_flowlabel;
199
200 /*
201 * TCP over IPv4
202 */
203
204 if (addr_type == IPV6_ADDR_MAPPED) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800205 u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 struct sockaddr_in sin;
207
208 SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
209
210 if (__ipv6_only_sock(sk))
211 return -ENETUNREACH;
212
213 sin.sin_family = AF_INET;
214 sin.sin_port = usin->sin6_port;
215 sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
216
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800217 icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 sk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800219#ifdef CONFIG_TCP_MD5SIG
220 tp->af_specific = &tcp_sock_ipv6_mapped_specific;
221#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
224
225 if (err) {
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800226 icsk->icsk_ext_hdr_len = exthdrlen;
227 icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 sk->sk_backlog_rcv = tcp_v6_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800229#ifdef CONFIG_TCP_MD5SIG
230 tp->af_specific = &tcp_sock_ipv6_specific;
231#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 goto failure;
233 } else {
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000234 ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
235 ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
236 &np->rcv_saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
238
239 return err;
240 }
241
242 if (!ipv6_addr_any(&np->rcv_saddr))
243 saddr = &np->rcv_saddr;
244
245 fl.proto = IPPROTO_TCP;
246 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
247 ipv6_addr_copy(&fl.fl6_src,
248 (saddr ? saddr : &np->saddr));
249 fl.oif = sk->sk_bound_dev_if;
Brian Haley51953d52009-10-05 08:24:16 +0000250 fl.mark = sk->sk_mark;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 fl.fl_ip_dport = usin->sin6_port;
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000252 fl.fl_ip_sport = inet->inet_sport;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000254 final_p = fl6_update_dst(&fl, np->opt, &final);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700256 security_sk_classify_flow(sk, &fl);
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 err = ip6_dst_lookup(sk, &dst, &fl);
259 if (err)
260 goto failure;
261 if (final_p)
262 ipv6_addr_copy(&fl.fl6_dst, final_p);
263
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800264 err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
265 if (err < 0) {
David S. Miller14e50e52007-05-24 18:17:54 -0700266 if (err == -EREMOTE)
267 err = ip6_dst_blackhole(sk, &dst, &fl);
268 if (err < 0)
269 goto failure;
270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272 if (saddr == NULL) {
273 saddr = &fl.fl6_src;
274 ipv6_addr_copy(&np->rcv_saddr, saddr);
275 }
276
277 /* set the source address */
278 ipv6_addr_copy(&np->saddr, saddr);
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000279 inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Herbert Xuf83ef8c2006-06-30 13:37:03 -0700281 sk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -0700282 __ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
David S. Miller493f3772010-12-02 12:14:29 -0800284 rt = (struct rt6_info *) dst;
285 if (tcp_death_row.sysctl_tw_recycle &&
286 !tp->rx_opt.ts_recent_stamp &&
287 ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) {
288 struct inet_peer *peer = rt6_get_peer(rt);
289 /*
290 * VJ's idea. We save last timestamp seen from
291 * the destination in peer table, when entering state
292 * TIME-WAIT * and initialize rx_opt.ts_recent from it,
293 * when trying new connection.
294 */
295 if (peer) {
296 inet_peer_refcheck(peer);
297 if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
298 tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
299 tp->rx_opt.ts_recent = peer->tcp_ts;
300 }
301 }
302 }
303
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800304 icsk->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 if (np->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800306 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
307 np->opt->opt_nflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
310
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000311 inet->inet_dport = usin->sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 tcp_set_state(sk, TCP_SYN_SENT);
Arnaldo Carvalho de Melod8313f52005-12-13 23:25:44 -0800314 err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (err)
316 goto late_failure;
317
318 if (!tp->write_seq)
319 tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
320 np->daddr.s6_addr32,
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000321 inet->inet_sport,
322 inet->inet_dport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 err = tcp_connect(sk);
325 if (err)
326 goto late_failure;
327
328 return 0;
329
330late_failure:
331 tcp_set_state(sk, TCP_CLOSE);
332 __sk_dst_reset(sk);
333failure:
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000334 inet->inet_dport = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 sk->sk_route_caps = 0;
336 return err;
337}
338
339static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
Brian Haleyd5fdd6b2009-06-23 04:31:07 -0700340 u8 type, u8 code, int offset, __be32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -0300343 const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 struct ipv6_pinfo *np;
345 struct sock *sk;
346 int err;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900347 struct tcp_sock *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 __u32 seq;
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700349 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Pavel Emelyanovca12a1a2008-07-16 20:28:42 -0700351 sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -0800352 th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 if (sk == NULL) {
Denis V. Luneve41b5362008-10-08 10:33:26 -0700355 ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
356 ICMP6_MIB_INERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 return;
358 }
359
360 if (sk->sk_state == TCP_TIME_WAIT) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -0700361 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 return;
363 }
364
365 bh_lock_sock(sk);
366 if (sock_owned_by_user(sk))
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700367 NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 if (sk->sk_state == TCP_CLOSE)
370 goto out;
371
Stephen Hemmingere802af92010-04-22 15:24:53 -0700372 if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
373 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
374 goto out;
375 }
376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 tp = tcp_sk(sk);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900378 seq = ntohl(th->seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (sk->sk_state != TCP_LISTEN &&
380 !between(seq, tp->snd_una, tp->snd_nxt)) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700381 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 goto out;
383 }
384
385 np = inet6_sk(sk);
386
387 if (type == ICMPV6_PKT_TOOBIG) {
388 struct dst_entry *dst = NULL;
389
390 if (sock_owned_by_user(sk))
391 goto out;
392 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
393 goto out;
394
395 /* icmp should have updated the destination cache entry */
396 dst = __sk_dst_check(sk, np->dst_cookie);
397
398 if (dst == NULL) {
399 struct inet_sock *inet = inet_sk(sk);
400 struct flowi fl;
401
402 /* BUGGG_FUTURE: Again, it is not clear how
403 to handle rthdr case. Ignore this complexity
404 for now.
405 */
406 memset(&fl, 0, sizeof(fl));
407 fl.proto = IPPROTO_TCP;
408 ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
409 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
410 fl.oif = sk->sk_bound_dev_if;
Brian Haley51953d52009-10-05 08:24:16 +0000411 fl.mark = sk->sk_mark;
Eric Dumazetc720c7e82009-10-15 06:30:45 +0000412 fl.fl_ip_dport = inet->inet_dport;
413 fl.fl_ip_sport = inet->inet_sport;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -0700414 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
417 sk->sk_err_soft = -err;
418 goto out;
419 }
420
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800421 if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 sk->sk_err_soft = -err;
423 goto out;
424 }
425
426 } else
427 dst_hold(dst);
428
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -0800429 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 tcp_sync_mss(sk, dst_mtu(dst));
431 tcp_simple_retransmit(sk);
432 } /* else let the usual retransmit timer handle it */
433 dst_release(dst);
434 goto out;
435 }
436
437 icmpv6_err_convert(type, code, &err);
438
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700439 /* Might be for an request_sock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 switch (sk->sk_state) {
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700441 struct request_sock *req, **prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 case TCP_LISTEN:
443 if (sock_owned_by_user(sk))
444 goto out;
445
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -0800446 req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
447 &hdr->saddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (!req)
449 goto out;
450
451 /* ICMPs are not backlogged, hence we cannot get
452 * an established socket here.
453 */
Ilpo Järvinen547b7922008-07-25 21:43:18 -0700454 WARN_ON(req->sk != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700456 if (seq != tcp_rsk(req)->snt_isn) {
Pavel Emelyanovde0744a2008-07-16 20:31:16 -0700457 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 goto out;
459 }
460
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -0700461 inet_csk_reqsk_queue_drop(sk, req, prev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 goto out;
463
464 case TCP_SYN_SENT:
465 case TCP_SYN_RECV: /* Cannot happen.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900466 It can, it SYNs are crossed. --ANK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 if (!sock_owned_by_user(sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 sk->sk_err = err;
469 sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
470
471 tcp_done(sk);
472 } else
473 sk->sk_err_soft = err;
474 goto out;
475 }
476
477 if (!sock_owned_by_user(sk) && np->recverr) {
478 sk->sk_err = err;
479 sk->sk_error_report(sk);
480 } else
481 sk->sk_err_soft = err;
482
483out:
484 bh_unlock_sock(sk);
485 sock_put(sk);
486}
487
488
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000489static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
490 struct request_values *rvp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -0800492 struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 struct ipv6_pinfo *np = inet6_sk(sk);
494 struct sk_buff * skb;
495 struct ipv6_txoptions *opt = NULL;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000496 struct in6_addr * final_p, final;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 struct flowi fl;
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800498 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 int err = -1;
500
501 memset(&fl, 0, sizeof(fl));
502 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700503 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
504 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 fl.fl6_flowlabel = 0;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700506 fl.oif = treq->iif;
Brian Haley51953d52009-10-05 08:24:16 +0000507 fl.mark = sk->sk_mark;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700508 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
KOVACS Krisztianfd507032008-10-19 23:35:58 -0700509 fl.fl_ip_sport = inet_rsk(req)->loc_port;
Venkat Yekkirala4237c752006-07-24 23:32:50 -0700510 security_req_classify_flow(req, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800512 opt = np->opt;
Arnaud Ebalard20c59de2010-06-01 21:35:01 +0000513 final_p = fl6_update_dst(&fl, opt, &final);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800515 err = ip6_dst_lookup(sk, &dst, &fl);
516 if (err)
517 goto done;
518 if (final_p)
519 ipv6_addr_copy(&fl.fl6_dst, final_p);
Alexey Dobriyan52479b62008-11-25 17:35:18 -0800520 if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
Denis V. Lunevfd80eb92008-02-29 11:43:03 -0800521 goto done;
522
William Allen Simpsone6b4d112009-12-02 18:07:39 +0000523 skb = tcp_make_synack(sk, dst, req, rvp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (skb) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000525 __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700527 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
Shan Wei4e15ed42010-04-15 16:43:08 +0000528 err = ip6_xmit(sk, skb, &fl, opt);
Gerrit Renkerb9df3cb2006-11-14 11:21:36 -0200529 err = net_xmit_eval(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 }
531
532done:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900533 if (opt && opt != np->opt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 sock_kfree_s(sk, opt, opt->tot_len);
Eric W. Biederman78b91042006-01-31 17:51:44 -0800535 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 return err;
537}
538
Octavian Purdila72659ec2010-01-17 19:09:39 -0800539static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
540 struct request_values *rvp)
541{
542 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
543 return tcp_v6_send_synack(sk, req, rvp);
544}
545
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800546static inline void syn_flood_warning(struct sk_buff *skb)
547{
548#ifdef CONFIG_SYN_COOKIES
549 if (sysctl_tcp_syncookies)
550 printk(KERN_INFO
551 "TCPv6: Possible SYN flooding on port %d. "
552 "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
553 else
554#endif
555 printk(KERN_INFO
556 "TCPv6: Possible SYN flooding on port %d. "
557 "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
558}
559
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700560static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
Wei Yongjun800d55f2009-02-23 21:45:33 +0000562 kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}
564
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800565#ifdef CONFIG_TCP_MD5SIG
566static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
567 struct in6_addr *addr)
568{
569 struct tcp_sock *tp = tcp_sk(sk);
570 int i;
571
572 BUG_ON(tp == NULL);
573
574 if (!tp->md5sig_info || !tp->md5sig_info->entries6)
575 return NULL;
576
577 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900578 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr))
David S. Millerf8ab18d2007-09-28 15:18:35 -0700579 return &tp->md5sig_info->keys6[i].base;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800580 }
581 return NULL;
582}
583
584static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
585 struct sock *addr_sk)
586{
587 return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
588}
589
590static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
591 struct request_sock *req)
592{
593 return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
594}
595
596static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
597 char *newkey, u8 newkeylen)
598{
599 /* Add key to the list */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700600 struct tcp_md5sig_key *key;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800601 struct tcp_sock *tp = tcp_sk(sk);
602 struct tcp6_md5sig_key *keys;
603
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700604 key = tcp_v6_md5_do_lookup(sk, peer);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800605 if (key) {
606 /* modify existing entry - just update that one */
Matthias M. Dellwegb0a713e2007-10-29 20:55:27 -0700607 kfree(key->key);
608 key->key = newkey;
609 key->keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800610 } else {
611 /* reallocate new list if current one is full. */
612 if (!tp->md5sig_info) {
613 tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC);
614 if (!tp->md5sig_info) {
615 kfree(newkey);
616 return -ENOMEM;
617 }
Eric Dumazeta4654192010-05-16 00:36:33 -0700618 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800619 }
Wu Fengguangaa133072009-09-02 23:45:45 -0700620 if (tcp_alloc_md5sig_pool(sk) == NULL) {
YOSHIFUJI Hideakiaacbe8c2007-11-20 17:30:56 -0800621 kfree(newkey);
622 return -ENOMEM;
623 }
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800624 if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) {
625 keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) *
626 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
627
628 if (!keys) {
629 tcp_free_md5sig_pool();
630 kfree(newkey);
631 return -ENOMEM;
632 }
633
634 if (tp->md5sig_info->entries6)
635 memmove(keys, tp->md5sig_info->keys6,
636 (sizeof (tp->md5sig_info->keys6[0]) *
637 tp->md5sig_info->entries6));
638
639 kfree(tp->md5sig_info->keys6);
640 tp->md5sig_info->keys6 = keys;
641 tp->md5sig_info->alloced6++;
642 }
643
644 ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr,
645 peer);
David S. Millerf8ab18d2007-09-28 15:18:35 -0700646 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;
647 tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800648
649 tp->md5sig_info->entries6++;
650 }
651 return 0;
652}
653
654static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk,
655 u8 *newkey, __u8 newkeylen)
656{
657 return tcp_v6_md5_do_add(sk, &inet6_sk(addr_sk)->daddr,
658 newkey, newkeylen);
659}
660
661static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer)
662{
663 struct tcp_sock *tp = tcp_sk(sk);
664 int i;
665
666 for (i = 0; i < tp->md5sig_info->entries6; i++) {
YOSHIFUJI Hideakicaad2952008-04-10 15:42:07 +0900667 if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800668 /* Free the key */
David S. Millerf8ab18d2007-09-28 15:18:35 -0700669 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800670 tp->md5sig_info->entries6--;
671
672 if (tp->md5sig_info->entries6 == 0) {
673 kfree(tp->md5sig_info->keys6);
674 tp->md5sig_info->keys6 = NULL;
YOSHIFUJI Hideakica983ce2007-07-24 15:27:30 -0700675 tp->md5sig_info->alloced6 = 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800676 } else {
677 /* shrink the database */
678 if (tp->md5sig_info->entries6 != i)
679 memmove(&tp->md5sig_info->keys6[i],
680 &tp->md5sig_info->keys6[i+1],
681 (tp->md5sig_info->entries6 - i)
682 * sizeof (tp->md5sig_info->keys6[0]));
683 }
YOSHIFUJI Hideaki77adefd2007-11-20 17:31:23 -0800684 tcp_free_md5sig_pool();
685 return 0;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800686 }
687 }
688 return -ENOENT;
689}
690
691static void tcp_v6_clear_md5_list (struct sock *sk)
692{
693 struct tcp_sock *tp = tcp_sk(sk);
694 int i;
695
696 if (tp->md5sig_info->entries6) {
697 for (i = 0; i < tp->md5sig_info->entries6; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700698 kfree(tp->md5sig_info->keys6[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800699 tp->md5sig_info->entries6 = 0;
700 tcp_free_md5sig_pool();
701 }
702
703 kfree(tp->md5sig_info->keys6);
704 tp->md5sig_info->keys6 = NULL;
705 tp->md5sig_info->alloced6 = 0;
706
707 if (tp->md5sig_info->entries4) {
708 for (i = 0; i < tp->md5sig_info->entries4; i++)
David S. Millerf8ab18d2007-09-28 15:18:35 -0700709 kfree(tp->md5sig_info->keys4[i].base.key);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800710 tp->md5sig_info->entries4 = 0;
711 tcp_free_md5sig_pool();
712 }
713
714 kfree(tp->md5sig_info->keys4);
715 tp->md5sig_info->keys4 = NULL;
716 tp->md5sig_info->alloced4 = 0;
717}
718
719static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
720 int optlen)
721{
722 struct tcp_md5sig cmd;
723 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
724 u8 *newkey;
725
726 if (optlen < sizeof(cmd))
727 return -EINVAL;
728
729 if (copy_from_user(&cmd, optval, sizeof(cmd)))
730 return -EFAULT;
731
732 if (sin6->sin6_family != AF_INET6)
733 return -EINVAL;
734
735 if (!cmd.tcpm_keylen) {
736 if (!tcp_sk(sk)->md5sig_info)
737 return -ENOENT;
Brian Haleye773e4f2007-08-24 23:16:08 -0700738 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800739 return tcp_v4_md5_do_del(sk, sin6->sin6_addr.s6_addr32[3]);
740 return tcp_v6_md5_do_del(sk, &sin6->sin6_addr);
741 }
742
743 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
744 return -EINVAL;
745
746 if (!tcp_sk(sk)->md5sig_info) {
747 struct tcp_sock *tp = tcp_sk(sk);
748 struct tcp_md5sig_info *p;
749
750 p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL);
751 if (!p)
752 return -ENOMEM;
753
754 tp->md5sig_info = p;
Eric Dumazeta4654192010-05-16 00:36:33 -0700755 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800756 }
757
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -0200758 newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800759 if (!newkey)
760 return -ENOMEM;
Brian Haleye773e4f2007-08-24 23:16:08 -0700761 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800762 return tcp_v4_md5_do_add(sk, sin6->sin6_addr.s6_addr32[3],
763 newkey, cmd.tcpm_keylen);
764 }
765 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
766}
767
Adam Langley49a72df2008-07-19 00:01:42 -0700768static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
769 struct in6_addr *daddr,
770 struct in6_addr *saddr, int nbytes)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800771{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800772 struct tcp6_pseudohdr *bp;
Adam Langley49a72df2008-07-19 00:01:42 -0700773 struct scatterlist sg;
YOSHIFUJI Hideaki8d26d762008-04-17 13:19:16 +0900774
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800775 bp = &hp->md5_blk.ip6;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800776 /* 1. TCP pseudo-header (RFC2460) */
777 ipv6_addr_copy(&bp->saddr, saddr);
778 ipv6_addr_copy(&bp->daddr, daddr);
Adam Langley49a72df2008-07-19 00:01:42 -0700779 bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley00b13042008-07-31 21:36:07 -0700780 bp->len = cpu_to_be32(nbytes);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800781
Adam Langley49a72df2008-07-19 00:01:42 -0700782 sg_init_one(&sg, bp, sizeof(*bp));
783 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
784}
David S. Millerc7da57a2007-10-26 00:41:21 -0700785
Adam Langley49a72df2008-07-19 00:01:42 -0700786static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
787 struct in6_addr *daddr, struct in6_addr *saddr,
788 struct tcphdr *th)
789{
790 struct tcp_md5sig_pool *hp;
791 struct hash_desc *desc;
792
793 hp = tcp_get_md5sig_pool();
794 if (!hp)
795 goto clear_hash_noput;
796 desc = &hp->md5_desc;
797
798 if (crypto_hash_init(desc))
799 goto clear_hash;
800 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
801 goto clear_hash;
802 if (tcp_md5_hash_header(hp, th))
803 goto clear_hash;
804 if (tcp_md5_hash_key(hp, key))
805 goto clear_hash;
806 if (crypto_hash_final(desc, md5_hash))
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800807 goto clear_hash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800808
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800809 tcp_put_md5sig_pool();
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800810 return 0;
Adam Langley49a72df2008-07-19 00:01:42 -0700811
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800812clear_hash:
813 tcp_put_md5sig_pool();
814clear_hash_noput:
815 memset(md5_hash, 0, 16);
Adam Langley49a72df2008-07-19 00:01:42 -0700816 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800817}
818
Adam Langley49a72df2008-07-19 00:01:42 -0700819static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
820 struct sock *sk, struct request_sock *req,
821 struct sk_buff *skb)
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800822{
823 struct in6_addr *saddr, *daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700824 struct tcp_md5sig_pool *hp;
825 struct hash_desc *desc;
826 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800827
828 if (sk) {
829 saddr = &inet6_sk(sk)->saddr;
830 daddr = &inet6_sk(sk)->daddr;
Adam Langley49a72df2008-07-19 00:01:42 -0700831 } else if (req) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800832 saddr = &inet6_rsk(req)->loc_addr;
833 daddr = &inet6_rsk(req)->rmt_addr;
Adam Langley49a72df2008-07-19 00:01:42 -0700834 } else {
835 struct ipv6hdr *ip6h = ipv6_hdr(skb);
836 saddr = &ip6h->saddr;
837 daddr = &ip6h->daddr;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800838 }
Adam Langley49a72df2008-07-19 00:01:42 -0700839
840 hp = tcp_get_md5sig_pool();
841 if (!hp)
842 goto clear_hash_noput;
843 desc = &hp->md5_desc;
844
845 if (crypto_hash_init(desc))
846 goto clear_hash;
847
848 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
849 goto clear_hash;
850 if (tcp_md5_hash_header(hp, th))
851 goto clear_hash;
852 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
853 goto clear_hash;
854 if (tcp_md5_hash_key(hp, key))
855 goto clear_hash;
856 if (crypto_hash_final(desc, md5_hash))
857 goto clear_hash;
858
859 tcp_put_md5sig_pool();
860 return 0;
861
862clear_hash:
863 tcp_put_md5sig_pool();
864clear_hash_noput:
865 memset(md5_hash, 0, 16);
866 return 1;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800867}
868
869static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
870{
871 __u8 *hash_location = NULL;
872 struct tcp_md5sig_key *hash_expected;
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700873 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700874 struct tcphdr *th = tcp_hdr(skb);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800875 int genhash;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800876 u8 newhash[16];
877
878 hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
YOSHIFUJI Hideaki7d5d5522008-04-17 12:29:53 +0900879 hash_location = tcp_parse_md5sig_option(th);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800880
David S. Miller785957d2008-07-30 03:03:15 -0700881 /* We've parsed the options - do we have a hash? */
882 if (!hash_expected && !hash_location)
883 return 0;
884
885 if (hash_expected && !hash_location) {
886 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800887 return 1;
888 }
889
David S. Miller785957d2008-07-30 03:03:15 -0700890 if (!hash_expected && hash_location) {
891 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800892 return 1;
893 }
894
895 /* check the signature */
Adam Langley49a72df2008-07-19 00:01:42 -0700896 genhash = tcp_v6_md5_hash_skb(newhash,
897 hash_expected,
898 NULL, NULL, skb);
899
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800900 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
901 if (net_ratelimit()) {
Joe Perches5856b602010-01-08 00:59:52 -0800902 printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800903 genhash ? "failed" : "mismatch",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700904 &ip6h->saddr, ntohs(th->source),
905 &ip6h->daddr, ntohs(th->dest));
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800906 }
907 return 1;
908 }
909 return 0;
910}
911#endif
912
Glenn Griffinc6aefaf2008-02-07 21:49:26 -0800913struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 .family = AF_INET6,
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -0700915 .obj_size = sizeof(struct tcp6_request_sock),
Octavian Purdila72659ec2010-01-17 19:09:39 -0800916 .rtx_syn_ack = tcp_v6_rtx_synack,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -0700917 .send_ack = tcp_v6_reqsk_send_ack,
918 .destructor = tcp_v6_reqsk_destructor,
Octavian Purdila72659ec2010-01-17 19:09:39 -0800919 .send_reset = tcp_v6_send_reset,
920 .syn_ack_timeout = tcp_syn_ack_timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921};
922
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800923#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3de2009-09-01 19:25:03 +0000924static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800925 .md5_lookup = tcp_v6_reqsk_md5_lookup,
John Dykstrae3afe7b2009-07-16 05:04:51 +0000926 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800927};
Andrew Mortonb6332e62006-11-30 19:16:28 -0800928#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -0800929
Herbert Xu8ad50d92010-04-11 02:15:54 +0000930static void __tcp_v6_send_check(struct sk_buff *skb,
931 struct in6_addr *saddr, struct in6_addr *daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700933 struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Patrick McHardy84fa7932006-08-29 16:44:56 -0700935 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000936 th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
Herbert Xu663ead32007-04-09 11:59:07 -0700937 skb->csum_start = skb_transport_header(skb) - skb->head;
Al Viroff1dcad2006-11-20 18:07:29 -0800938 skb->csum_offset = offsetof(struct tcphdr, check);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 } else {
Herbert Xu8ad50d92010-04-11 02:15:54 +0000940 th->check = tcp_v6_check(skb->len, saddr, daddr,
941 csum_partial(th, th->doff << 2,
942 skb->csum));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944}
945
Herbert Xubb296242010-04-11 02:15:55 +0000946static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
Herbert Xu8ad50d92010-04-11 02:15:54 +0000947{
948 struct ipv6_pinfo *np = inet6_sk(sk);
949
950 __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
951}
952
Herbert Xua430a432006-07-08 13:34:56 -0700953static int tcp_v6_gso_send_check(struct sk_buff *skb)
954{
955 struct ipv6hdr *ipv6h;
956 struct tcphdr *th;
957
958 if (!pskb_may_pull(skb, sizeof(*th)))
959 return -EINVAL;
960
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700961 ipv6h = ipv6_hdr(skb);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -0700962 th = tcp_hdr(skb);
Herbert Xua430a432006-07-08 13:34:56 -0700963
964 th->check = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -0700965 skb->ip_summed = CHECKSUM_PARTIAL;
Herbert Xu8ad50d92010-04-11 02:15:54 +0000966 __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
Herbert Xua430a432006-07-08 13:34:56 -0700967 return 0;
968}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Herbert Xu36990672009-05-22 00:45:28 -0700970static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
971 struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800972{
Herbert Xu36e7b1b2009-04-27 05:44:45 -0700973 struct ipv6hdr *iph = skb_gro_network_header(skb);
Herbert Xu684f2172009-01-08 10:41:23 -0800974
975 switch (skb->ip_summed) {
976 case CHECKSUM_COMPLETE:
Herbert Xu86911732009-01-29 14:19:50 +0000977 if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
Herbert Xu684f2172009-01-08 10:41:23 -0800978 skb->csum)) {
979 skb->ip_summed = CHECKSUM_UNNECESSARY;
980 break;
981 }
982
983 /* fall through */
984 case CHECKSUM_NONE:
985 NAPI_GRO_CB(skb)->flush = 1;
986 return NULL;
987 }
988
989 return tcp_gro_receive(head, skb);
990}
Herbert Xu684f2172009-01-08 10:41:23 -0800991
Herbert Xu36990672009-05-22 00:45:28 -0700992static int tcp6_gro_complete(struct sk_buff *skb)
Herbert Xu684f2172009-01-08 10:41:23 -0800993{
994 struct ipv6hdr *iph = ipv6_hdr(skb);
995 struct tcphdr *th = tcp_hdr(skb);
996
997 th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
998 &iph->saddr, &iph->daddr, 0);
999 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
1000
1001 return tcp_gro_complete(skb);
1002}
Herbert Xu684f2172009-01-08 10:41:23 -08001003
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001004static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
1005 u32 ts, struct tcp_md5sig_key *key, int rst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001007 struct tcphdr *th = tcp_hdr(skb), *t1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 struct sk_buff *buff;
1009 struct flowi fl;
Eric Dumazetadf30902009-06-02 05:19:30 +00001010 struct net *net = dev_net(skb_dst(skb)->dev);
Daniel Lezcanoe5047992008-03-07 11:16:26 -08001011 struct sock *ctl_sk = net->ipv6.tcp_sk;
YOSHIFUJI Hideaki9cb57342008-01-12 02:16:03 -08001012 unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazetadf30902009-06-02 05:19:30 +00001013 struct dst_entry *dst;
Al Viroe69a4ad2006-11-14 20:56:00 -08001014 __be32 *topt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 if (ts)
YOSHIFUJI Hideaki4244f8a2006-10-10 19:40:50 -07001017 tot_len += TCPOLEN_TSTAMP_ALIGNED;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001018#ifdef CONFIG_TCP_MD5SIG
1019 if (key)
1020 tot_len += TCPOLEN_MD5SIG_ALIGNED;
1021#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
1024 GFP_ATOMIC);
1025 if (buff == NULL)
1026 return;
1027
1028 skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
1029
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001030 t1 = (struct tcphdr *) skb_push(buff, tot_len);
Herbert Xu6651ffc2010-04-21 00:47:15 -07001031 skb_reset_transport_header(buff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 /* Swap the send and the receive. */
1034 memset(t1, 0, sizeof(*t1));
1035 t1->dest = th->source;
1036 t1->source = th->dest;
Ilpo Järvinen77c676d2008-10-09 14:41:38 -07001037 t1->doff = tot_len / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 t1->seq = htonl(seq);
1039 t1->ack_seq = htonl(ack);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001040 t1->ack = !rst || !th->ack;
1041 t1->rst = rst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 t1->window = htons(win);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001043
Al Viroe69a4ad2006-11-14 20:56:00 -08001044 topt = (__be32 *)(t1 + 1);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 if (ts) {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001047 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1048 (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
1049 *topt++ = htonl(tcp_time_stamp);
Ilpo Järvinen53b12572008-10-08 14:36:33 -07001050 *topt++ = htonl(ts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
1052
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001053#ifdef CONFIG_TCP_MD5SIG
1054 if (key) {
1055 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1056 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
Adam Langley49a72df2008-07-19 00:01:42 -07001057 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
Adam Langley90b7e112008-07-31 20:49:48 -07001058 &ipv6_hdr(skb)->saddr,
1059 &ipv6_hdr(skb)->daddr, t1);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001060 }
1061#endif
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 memset(&fl, 0, sizeof(fl));
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001064 ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
1065 ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
David S. Millere5700af2010-04-21 14:59:20 -07001067 buff->ip_summed = CHECKSUM_PARTIAL;
1068 buff->csum = 0;
1069
Herbert Xu8ad50d92010-04-11 02:15:54 +00001070 __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 fl.proto = IPPROTO_TCP;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001073 fl.oif = inet6_iif(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 fl.fl_ip_dport = t1->dest;
1075 fl.fl_ip_sport = t1->source;
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07001076 security_skb_classify_flow(skb, &fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001078 /* Pass a socket to ip6_dst_lookup either it is for RST
1079 * Underlying function will use this to retrieve the network
1080 * namespace
1081 */
Eric Dumazetadf30902009-06-02 05:19:30 +00001082 if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
1083 if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
1084 skb_dst_set(buff, dst);
Shan Wei4e15ed42010-04-15 16:43:08 +00001085 ip6_xmit(ctl_sk, buff, &fl, NULL);
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001086 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001087 if (rst)
1088 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return;
Arnaldo Carvalho de Meloecc51b62005-12-12 14:38:10 -08001090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092
1093 kfree_skb(buff);
1094}
1095
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001096static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
1097{
1098 struct tcphdr *th = tcp_hdr(skb);
1099 u32 seq = 0, ack_seq = 0;
Guo-Fu Tsengfa3e5b42008-10-09 21:11:56 -07001100 struct tcp_md5sig_key *key = NULL;
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001101
1102 if (th->rst)
1103 return;
1104
1105 if (!ipv6_unicast_destination(skb))
1106 return;
1107
1108#ifdef CONFIG_TCP_MD5SIG
1109 if (sk)
1110 key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
Ilpo Järvinen626e2642008-10-09 14:42:40 -07001111#endif
1112
1113 if (th->ack)
1114 seq = ntohl(th->ack_seq);
1115 else
1116 ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
1117 (th->doff << 2);
1118
1119 tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1);
1120}
1121
1122static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
1123 struct tcp_md5sig_key *key)
1124{
1125 tcp_v6_send_response(skb, seq, ack, win, ts, key, 0);
1126}
1127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
1129{
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001130 struct inet_timewait_sock *tw = inet_twsk(sk);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001131 struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001133 tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001134 tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001135 tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07001137 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138}
1139
Gui Jianfeng6edafaa2008-08-06 23:50:04 -07001140static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
1141 struct request_sock *req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
YOSHIFUJI Hideaki9501f972008-04-18 12:45:16 +09001143 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 -07001144 tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145}
1146
1147
1148static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
1149{
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001150 struct request_sock *req, **prev;
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001151 const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 struct sock *nsk;
1153
1154 /* Find possible connection requests. */
Arnaldo Carvalho de Melo81297652005-12-13 23:15:24 -08001155 req = inet6_csk_search_req(sk, &prev, th->source,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001156 &ipv6_hdr(skb)->saddr,
1157 &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (req)
1159 return tcp_check_req(sk, skb, req, prev);
1160
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001161 nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
Pavel Emelyanovd86e0da2008-01-31 05:07:21 -08001162 &ipv6_hdr(skb)->saddr, th->source,
1163 &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
1165 if (nsk) {
1166 if (nsk->sk_state != TCP_TIME_WAIT) {
1167 bh_lock_sock(nsk);
1168 return nsk;
1169 }
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001170 inet_twsk_put(inet_twsk(nsk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return NULL;
1172 }
1173
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001174#ifdef CONFIG_SYN_COOKIES
Florian Westphalaf9b4732010-06-03 00:43:44 +00001175 if (!th->syn)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001176 sk = cookie_v6_check(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177#endif
1178 return sk;
1179}
1180
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181/* FIXME: this is substantially similar to the ipv4 code.
1182 * Can some kind of merge be done? -- erics
1183 */
1184static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1185{
William Allen Simpson4957faade2009-12-02 18:25:27 +00001186 struct tcp_extend_values tmp_ext;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001187 struct tcp_options_received tmp_opt;
William Allen Simpson4957faade2009-12-02 18:25:27 +00001188 u8 *hash_location;
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001189 struct request_sock *req;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001190 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 struct ipv6_pinfo *np = inet6_sk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 struct tcp_sock *tp = tcp_sk(sk);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001193 __u32 isn = TCP_SKB_CB(skb)->when;
David S. Miller493f3772010-12-02 12:14:29 -08001194 struct dst_entry *dst = NULL;
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001195#ifdef CONFIG_SYN_COOKIES
1196 int want_cookie = 0;
1197#else
1198#define want_cookie 0
1199#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 if (skb->protocol == htons(ETH_P_IP))
1202 return tcp_v4_conn_request(sk, skb);
1203
1204 if (!ipv6_unicast_destination(skb))
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001205 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001207 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (net_ratelimit())
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001209 syn_flood_warning(skb);
1210#ifdef CONFIG_SYN_COOKIES
1211 if (sysctl_tcp_syncookies)
1212 want_cookie = 1;
1213 else
1214#endif
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001215 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07001218 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 goto drop;
1220
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001221 req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 if (req == NULL)
1223 goto drop;
1224
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001225#ifdef CONFIG_TCP_MD5SIG
1226 tcp_rsk(req)->af_specific = &tcp_request_sock_ipv6_ops;
1227#endif
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 tcp_clear_options(&tmp_opt);
1230 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1231 tmp_opt.user_mss = tp->rx_opt.user_mss;
David S. Millerbb5b7c12009-12-15 20:56:42 -08001232 tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
William Allen Simpson4957faade2009-12-02 18:25:27 +00001234 if (tmp_opt.cookie_plus > 0 &&
1235 tmp_opt.saw_tstamp &&
1236 !tp->rx_opt.cookie_out_never &&
1237 (sysctl_tcp_cookie_size > 0 ||
1238 (tp->cookie_values != NULL &&
1239 tp->cookie_values->cookie_desired > 0))) {
1240 u8 *c;
1241 u32 *d;
1242 u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
1243 int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
1244
1245 if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
1246 goto drop_and_free;
1247
1248 /* Secret recipe starts with IP addresses */
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001249 d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
William Allen Simpson4957faade2009-12-02 18:25:27 +00001250 *mess++ ^= *d++;
1251 *mess++ ^= *d++;
1252 *mess++ ^= *d++;
1253 *mess++ ^= *d++;
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001254 d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
William Allen Simpson4957faade2009-12-02 18:25:27 +00001255 *mess++ ^= *d++;
1256 *mess++ ^= *d++;
1257 *mess++ ^= *d++;
1258 *mess++ ^= *d++;
1259
1260 /* plus variable length Initiator Cookie */
1261 c = (u8 *)mess;
1262 while (l-- > 0)
1263 *c++ ^= *hash_location++;
1264
1265#ifdef CONFIG_SYN_COOKIES
1266 want_cookie = 0; /* not our kind of cookie */
1267#endif
1268 tmp_ext.cookie_out_never = 0; /* false */
1269 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1270 } else if (!tp->rx_opt.cookie_in_always) {
1271 /* redundant indications, but ensure initialization. */
1272 tmp_ext.cookie_out_never = 1; /* true */
1273 tmp_ext.cookie_plus = 0;
1274 } else {
1275 goto drop_and_free;
1276 }
1277 tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278
Florian Westphal4dfc2812008-04-10 03:12:40 -07001279 if (want_cookie && !tmp_opt.saw_tstamp)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001280 tcp_clear_options(&tmp_opt);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
1283 tcp_openreq_init(req, &tmp_opt, skb);
1284
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08001285 treq = inet6_rsk(req);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001286 ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
1287 ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
Florian Westphal172d69e2010-06-21 11:48:45 +00001288 if (!want_cookie || tmp_opt.tstamp_ok)
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001289 TCP_ECN_create_request(req, tcp_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Florian Westphal2bbdf382010-06-13 11:29:39 +00001291 if (!isn) {
David S. Miller493f3772010-12-02 12:14:29 -08001292 struct inet_peer *peer = NULL;
1293
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001294 if (ipv6_opt_accepted(sk, skb) ||
1295 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1296 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
1297 atomic_inc(&skb->users);
1298 treq->pktopts = skb;
1299 }
1300 treq->iif = sk->sk_bound_dev_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001302 /* So that link locals have meaning */
1303 if (!sk->sk_bound_dev_if &&
1304 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1305 treq->iif = inet6_iif(skb);
David S. Miller493f3772010-12-02 12:14:29 -08001306
1307 if (want_cookie) {
Florian Westphal2bbdf382010-06-13 11:29:39 +00001308 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
1309 req->cookie_ts = tmp_opt.tstamp_ok;
David S. Miller493f3772010-12-02 12:14:29 -08001310 goto have_isn;
Florian Westphal2bbdf382010-06-13 11:29:39 +00001311 }
David S. Miller493f3772010-12-02 12:14:29 -08001312
1313 /* VJ's idea. We save last timestamp seen
1314 * from the destination in peer table, when entering
1315 * state TIME-WAIT, and check against it before
1316 * accepting new connection request.
1317 *
1318 * If "isn" is not zero, this request hit alive
1319 * timewait bucket, so that all the necessary checks
1320 * are made in the function processing timewait state.
1321 */
1322 if (tmp_opt.saw_tstamp &&
1323 tcp_death_row.sysctl_tw_recycle &&
1324 (dst = inet6_csk_route_req(sk, req)) != NULL &&
1325 (peer = rt6_get_peer((struct rt6_info *)dst)) != NULL &&
1326 ipv6_addr_equal((struct in6_addr *)peer->daddr.a6,
1327 &treq->rmt_addr)) {
1328 inet_peer_refcheck(peer);
1329 if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
1330 (s32)(peer->tcp_ts - req->ts_recent) >
1331 TCP_PAWS_WINDOW) {
1332 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
1333 goto drop_and_release;
1334 }
1335 }
1336 /* Kill the following clause, if you dislike this way. */
1337 else if (!sysctl_tcp_syncookies &&
1338 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
1339 (sysctl_max_syn_backlog >> 2)) &&
1340 (!peer || !peer->tcp_ts_stamp) &&
1341 (!dst || !dst_metric(dst, RTAX_RTT))) {
1342 /* Without syncookies last quarter of
1343 * backlog is filled with destinations,
1344 * proven to be alive.
1345 * It means that we continue to communicate
1346 * to destinations, already remembered
1347 * to the moment of synflood.
1348 */
1349 LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n",
1350 &treq->rmt_addr, ntohs(tcp_hdr(skb)->source));
1351 goto drop_and_release;
1352 }
1353
1354 isn = tcp_v6_init_sequence(skb);
Glenn Griffinc6aefaf2008-02-07 21:49:26 -08001355 }
David S. Miller493f3772010-12-02 12:14:29 -08001356have_isn:
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001357 tcp_rsk(req)->snt_isn = isn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Venkat Yekkirala4237c752006-07-24 23:32:50 -07001359 security_inet_conn_request(sk, skb, req);
1360
William Allen Simpson4957faade2009-12-02 18:25:27 +00001361 if (tcp_v6_send_synack(sk, req,
1362 (struct request_values *)&tmp_ext) ||
1363 want_cookie)
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001364 goto drop_and_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001366 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1367 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
David S. Miller493f3772010-12-02 12:14:29 -08001369drop_and_release:
1370 dst_release(dst);
William Allen Simpsone6b4d112009-12-02 18:07:39 +00001371drop_and_free:
1372 reqsk_free(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373drop:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 return 0; /* don't send reset */
1375}
1376
1377static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07001378 struct request_sock *req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 struct dst_entry *dst)
1380{
Vegard Nossum78d15e82008-09-12 16:17:43 -07001381 struct inet6_request_sock *treq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
1383 struct tcp6_sock *newtcp6sk;
1384 struct inet_sock *newinet;
1385 struct tcp_sock *newtp;
1386 struct sock *newsk;
1387 struct ipv6_txoptions *opt;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001388#ifdef CONFIG_TCP_MD5SIG
1389 struct tcp_md5sig_key *key;
1390#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
1392 if (skb->protocol == htons(ETH_P_IP)) {
1393 /*
1394 * v6 mapped
1395 */
1396
1397 newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
1398
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001399 if (newsk == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 return NULL;
1401
1402 newtcp6sk = (struct tcp6_sock *)newsk;
1403 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1404
1405 newinet = inet_sk(newsk);
1406 newnp = inet6_sk(newsk);
1407 newtp = tcp_sk(newsk);
1408
1409 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1410
Eric Dumazetc720c7e82009-10-15 06:30:45 +00001411 ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Eric Dumazetc720c7e82009-10-15 06:30:45 +00001413 ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
1415 ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
1416
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001417 inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 newsk->sk_backlog_rcv = tcp_v4_do_rcv;
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001419#ifdef CONFIG_TCP_MD5SIG
1420 newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
1421#endif
1422
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 newnp->pktoptions = NULL;
1424 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001425 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001426 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001428 /*
1429 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1430 * here, tcp_create_openreq_child now does this for us, see the comment in
1431 * that function for the gory details. -acme
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
1434 /* It is tricky place. Until this moment IPv4 tcp
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001435 worked with IPv6 icsk.icsk_af_ops.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 Sync it now.
1437 */
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001438 tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440 return newsk;
1441 }
1442
Vegard Nossum78d15e82008-09-12 16:17:43 -07001443 treq = inet6_rsk(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 opt = np->opt;
1445
1446 if (sk_acceptq_is_full(sk))
1447 goto out_overflow;
1448
David S. Miller493f3772010-12-02 12:14:29 -08001449 if (!dst) {
1450 dst = inet6_csk_route_req(sk, req);
1451 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 goto out;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001453 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455 newsk = tcp_create_openreq_child(sk, req, skb);
1456 if (newsk == NULL)
Balazs Scheidler093d2822010-10-21 13:06:43 +02001457 goto out_nonewsk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Arnaldo Carvalho de Meloe6848972005-08-09 19:45:38 -07001459 /*
1460 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1461 * count here, tcp_create_openreq_child now does this for us, see the
1462 * comment in that function for the gory details. -acme
1463 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Stephen Hemminger59eed272006-08-25 15:55:43 -07001465 newsk->sk_gso_type = SKB_GSO_TCPV6;
YOSHIFUJI Hideaki8e1ef0a2006-08-29 17:15:09 -07001466 __ip6_dst_store(newsk, dst, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 newtcp6sk = (struct tcp6_sock *)newsk;
1469 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1470
1471 newtp = tcp_sk(newsk);
1472 newinet = inet_sk(newsk);
1473 newnp = inet6_sk(newsk);
1474
1475 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1476
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001477 ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr);
1478 ipv6_addr_copy(&newnp->saddr, &treq->loc_addr);
1479 ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr);
1480 newsk->sk_bound_dev_if = treq->iif;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001482 /* Now IPv6 options...
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484 First: no IPv4 options.
1485 */
1486 newinet->opt = NULL;
Masayuki Nakagawad35690b2007-03-16 16:14:03 -07001487 newnp->ipv6_fl_list = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
1489 /* Clone RX bits */
1490 newnp->rxopt.all = np->rxopt.all;
1491
1492 /* Clone pktoptions received with SYN */
1493 newnp->pktoptions = NULL;
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07001494 if (treq->pktopts != NULL) {
1495 newnp->pktoptions = skb_clone(treq->pktopts, GFP_ATOMIC);
1496 kfree_skb(treq->pktopts);
1497 treq->pktopts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 if (newnp->pktoptions)
1499 skb_set_owner_r(newnp->pktoptions, newsk);
1500 }
1501 newnp->opt = NULL;
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001502 newnp->mcast_oif = inet6_iif(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001503 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 /* Clone native IPv6 options from listening socket (if any)
1506
1507 Yes, keeping reference count would be much more clever,
1508 but we make one more one thing there: reattach optmem
1509 to newsk.
1510 */
1511 if (opt) {
1512 newnp->opt = ipv6_dup_options(newsk, opt);
1513 if (opt != np->opt)
1514 sock_kfree_s(sk, opt, opt->tot_len);
1515 }
1516
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001517 inet_csk(newsk)->icsk_ext_hdr_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 if (newnp->opt)
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001519 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
1520 newnp->opt->opt_flen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
John Heffner5d424d52006-03-20 17:53:41 -08001522 tcp_mtup_init(newsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 tcp_sync_mss(newsk, dst_mtu(dst));
1524 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1525 tcp_initialize_rcv_mss(newsk);
1526
Eric Dumazetc720c7e82009-10-15 06:30:45 +00001527 newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
1528 newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001530#ifdef CONFIG_TCP_MD5SIG
1531 /* Copy over the MD5 key from the original socket */
1532 if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) {
1533 /* We're using one, so create a matching key
1534 * on the newsk structure. If we fail to get
1535 * memory, then we end up not copying the key
1536 * across. Shucks.
1537 */
Arnaldo Carvalho de Meloaf879cc2006-11-17 12:14:37 -02001538 char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
1539 if (newkey != NULL)
John Dykstrae547bc12009-07-17 09:23:22 +00001540 tcp_v6_md5_do_add(newsk, &newnp->daddr,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001541 newkey, key->keylen);
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001542 }
1543#endif
1544
Balazs Scheidler093d2822010-10-21 13:06:43 +02001545 if (__inet_inherit_port(sk, newsk) < 0) {
1546 sock_put(newsk);
1547 goto out;
1548 }
Eric Dumazet9327f702009-12-04 03:46:54 +00001549 __inet6_hash(newsk, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
1551 return newsk;
1552
1553out_overflow:
Pavel Emelyanovde0744a2008-07-16 20:31:16 -07001554 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001555out_nonewsk:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 if (opt && opt != np->opt)
1557 sock_kfree_s(sk, opt, opt->tot_len);
1558 dst_release(dst);
Balazs Scheidler093d2822010-10-21 13:06:43 +02001559out:
1560 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 return NULL;
1562}
1563
Al Virob51655b2006-11-14 21:40:42 -08001564static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565{
Patrick McHardy84fa7932006-08-29 16:44:56 -07001566 if (skb->ip_summed == CHECKSUM_COMPLETE) {
Herbert Xu684f2172009-01-08 10:41:23 -08001567 if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001568 &ipv6_hdr(skb)->daddr, skb->csum)) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001569 skb->ip_summed = CHECKSUM_UNNECESSARY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 return 0;
Herbert Xufb286bb2005-11-10 13:01:24 -08001571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
Herbert Xufb286bb2005-11-10 13:01:24 -08001573
Herbert Xu684f2172009-01-08 10:41:23 -08001574 skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001575 &ipv6_hdr(skb)->saddr,
1576 &ipv6_hdr(skb)->daddr, 0));
Herbert Xufb286bb2005-11-10 13:01:24 -08001577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (skb->len <= 76) {
Herbert Xufb286bb2005-11-10 13:01:24 -08001579 return __skb_checksum_complete(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 }
1581 return 0;
1582}
1583
1584/* The socket must have it's spinlock held when we get
1585 * here.
1586 *
1587 * We have a potential double-lock case here, so even when
1588 * doing backlog processing we use the BH locking scheme.
1589 * This is because we cannot sleep with the original spinlock
1590 * held.
1591 */
1592static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1593{
1594 struct ipv6_pinfo *np = inet6_sk(sk);
1595 struct tcp_sock *tp;
1596 struct sk_buff *opt_skb = NULL;
1597
1598 /* Imagine: socket is IPv6. IPv4 packet arrives,
1599 goes to IPv4 receive handler and backlogged.
1600 From backlog it always goes here. Kerboom...
1601 Fortunately, tcp_rcv_established and rcv_established
1602 handle them correctly, but it is not case with
1603 tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
1604 */
1605
1606 if (skb->protocol == htons(ETH_P_IP))
1607 return tcp_v4_do_rcv(sk, skb);
1608
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001609#ifdef CONFIG_TCP_MD5SIG
1610 if (tcp_v6_inbound_md5_hash (sk, skb))
1611 goto discard;
1612#endif
1613
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001614 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 goto discard;
1616
1617 /*
1618 * socket locking is here for SMP purposes as backlog rcv
1619 * is currently called with bh processing disabled.
1620 */
1621
1622 /* Do Stevens' IPV6_PKTOPTIONS.
1623
1624 Yes, guys, it is the only place in our code, where we
1625 may make it not affecting IPv4.
1626 The rest of code is protocol independent,
1627 and I do not like idea to uglify IPv4.
1628
1629 Actually, all the idea behind IPV6_PKTOPTIONS
1630 looks not very well thought. For now we latch
1631 options, received in the last packet, enqueued
1632 by tcp. Feel free to propose better solution.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001633 --ANK (980728)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 */
1635 if (np->rxopt.all)
1636 opt_skb = skb_clone(skb, GFP_ATOMIC);
1637
1638 if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1639 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001640 if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 goto reset;
1642 TCP_CHECK_TIMER(sk);
1643 if (opt_skb)
1644 goto ipv6_pktoptions;
1645 return 0;
1646 }
1647
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07001648 if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 goto csum_err;
1650
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001651 if (sk->sk_state == TCP_LISTEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 struct sock *nsk = tcp_v6_hnd_req(sk, skb);
1653 if (!nsk)
1654 goto discard;
1655
1656 /*
1657 * Queue it on the new socket if the new socket is active,
1658 * otherwise we just shortcircuit this and continue with
1659 * the new socket..
1660 */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001661 if(nsk != sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 if (tcp_child_process(sk, nsk, skb))
1663 goto reset;
1664 if (opt_skb)
1665 __kfree_skb(opt_skb);
1666 return 0;
1667 }
1668 }
1669
1670 TCP_CHECK_TIMER(sk);
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001671 if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 goto reset;
1673 TCP_CHECK_TIMER(sk);
1674 if (opt_skb)
1675 goto ipv6_pktoptions;
1676 return 0;
1677
1678reset:
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001679 tcp_v6_send_reset(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680discard:
1681 if (opt_skb)
1682 __kfree_skb(opt_skb);
1683 kfree_skb(skb);
1684 return 0;
1685csum_err:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001686 TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 goto discard;
1688
1689
1690ipv6_pktoptions:
1691 /* Do you ask, what is it?
1692
1693 1. skb was enqueued by tcp.
1694 2. skb is added to tail of read queue, rather than out of order.
1695 3. socket is not in passive state.
1696 4. Finally, it really contains options, which user wants to receive.
1697 */
1698 tp = tcp_sk(sk);
1699 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt &&
1700 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) {
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001701 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001702 np->mcast_oif = inet6_iif(opt_skb);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +09001703 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001704 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 if (ipv6_opt_accepted(sk, opt_skb)) {
1706 skb_set_owner_r(opt_skb, sk);
1707 opt_skb = xchg(&np->pktoptions, opt_skb);
1708 } else {
1709 __kfree_skb(opt_skb);
1710 opt_skb = xchg(&np->pktoptions, NULL);
1711 }
1712 }
1713
Wei Yongjun800d55f2009-02-23 21:45:33 +00001714 kfree_skb(opt_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 return 0;
1716}
1717
Herbert Xue5bbef22007-10-15 12:50:28 -07001718static int tcp_v6_rcv(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719{
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001720 struct tcphdr *th;
Stephen Hemmingere802af92010-04-22 15:24:53 -07001721 struct ipv6hdr *hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 struct sock *sk;
1723 int ret;
Pavel Emelyanova86b1e32008-07-16 20:20:58 -07001724 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 if (skb->pkt_type != PACKET_HOST)
1727 goto discard_it;
1728
1729 /*
1730 * Count it even if it's bad.
1731 */
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001732 TCP_INC_STATS_BH(net, TCP_MIB_INSEGS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
1734 if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
1735 goto discard_it;
1736
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001737 th = tcp_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
1739 if (th->doff < sizeof(struct tcphdr)/4)
1740 goto bad_packet;
1741 if (!pskb_may_pull(skb, th->doff*4))
1742 goto discard_it;
1743
Herbert Xu60476372007-04-09 11:59:39 -07001744 if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 goto bad_packet;
1746
Arnaldo Carvalho de Meloaa8223c2007-04-10 21:04:22 -07001747 th = tcp_hdr(skb);
Stephen Hemmingere802af92010-04-22 15:24:53 -07001748 hdr = ipv6_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1750 TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1751 skb->len - th->doff*4);
1752 TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1753 TCP_SKB_CB(skb)->when = 0;
Stephen Hemmingere802af92010-04-22 15:24:53 -07001754 TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 TCP_SKB_CB(skb)->sacked = 0;
1756
Arnaldo Carvalho de Melo9a1f27c2008-10-07 11:41:57 -07001757 sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (!sk)
1759 goto no_tcp_socket;
1760
1761process:
1762 if (sk->sk_state == TCP_TIME_WAIT)
1763 goto do_time_wait;
1764
Stephen Hemmingere802af92010-04-22 15:24:53 -07001765 if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) {
1766 NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
1767 goto discard_and_relse;
1768 }
1769
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
1771 goto discard_and_relse;
1772
Dmitry Mishinfda9ef52006-08-31 15:28:39 -07001773 if (sk_filter(sk, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 goto discard_and_relse;
1775
1776 skb->dev = NULL;
1777
Fabio Olive Leite293b9c42006-09-25 22:28:47 -07001778 bh_lock_sock_nested(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 ret = 0;
1780 if (!sock_owned_by_user(sk)) {
Chris Leech1a2449a2006-05-23 18:05:53 -07001781#ifdef CONFIG_NET_DMA
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001782 struct tcp_sock *tp = tcp_sk(sk);
David S. Millerb4caea82007-10-26 04:20:13 -07001783 if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
Dan Williamsf67b4592009-01-06 11:38:15 -07001784 tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY);
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09001785 if (tp->ucopy.dma_chan)
1786 ret = tcp_v6_do_rcv(sk, skb);
1787 else
Chris Leech1a2449a2006-05-23 18:05:53 -07001788#endif
1789 {
1790 if (!tcp_prequeue(sk, skb))
1791 ret = tcp_v6_do_rcv(sk, skb);
1792 }
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001793 } else if (unlikely(sk_add_backlog(sk, skb))) {
Zhu Yi6b03a532010-03-04 18:01:41 +00001794 bh_unlock_sock(sk);
Eric Dumazet6cce09f2010-03-07 23:21:57 +00001795 NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP);
Zhu Yi6b03a532010-03-04 18:01:41 +00001796 goto discard_and_relse;
1797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 bh_unlock_sock(sk);
1799
1800 sock_put(sk);
1801 return ret ? -1 : 0;
1802
1803no_tcp_socket:
1804 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
1805 goto discard_it;
1806
1807 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
1808bad_packet:
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001809 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 } else {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001811 tcp_v6_send_reset(NULL, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 }
1813
1814discard_it:
1815
1816 /*
1817 * Discard frame
1818 */
1819
1820 kfree_skb(skb);
1821 return 0;
1822
1823discard_and_relse:
1824 sock_put(sk);
1825 goto discard_it;
1826
1827do_time_wait:
1828 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001829 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 goto discard_it;
1831 }
1832
1833 if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
Pavel Emelyanov63231bd2008-07-16 20:22:25 -07001834 TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001835 inet_twsk_put(inet_twsk(sk));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 goto discard_it;
1837 }
1838
YOSHIFUJI Hideaki9469c7b2006-10-10 19:41:46 -07001839 switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 case TCP_TW_SYN:
1841 {
1842 struct sock *sk2;
1843
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09001844 sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -07001845 &ipv6_hdr(skb)->daddr,
Arnaldo Carvalho de Melo505cbfc2005-08-12 09:19:38 -03001846 ntohs(th->dest), inet6_iif(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 if (sk2 != NULL) {
Arnaldo Carvalho de Melo295ff7e2005-08-09 20:44:40 -07001848 struct inet_timewait_sock *tw = inet_twsk(sk);
1849 inet_twsk_deschedule(tw, &tcp_death_row);
1850 inet_twsk_put(tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 sk = sk2;
1852 goto process;
1853 }
1854 /* Fall through to ACK */
1855 }
1856 case TCP_TW_ACK:
1857 tcp_v6_timewait_ack(sk, skb);
1858 break;
1859 case TCP_TW_RST:
1860 goto no_tcp_socket;
1861 case TCP_TW_SUCCESS:;
1862 }
1863 goto discard_it;
1864}
1865
David S. Millerccb7c412010-12-01 18:09:13 -08001866static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867{
1868 /* Alas, not yet... */
David S. Miller3f419d22010-11-29 13:37:14 -08001869 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870}
1871
David S. Millerccb7c412010-12-01 18:09:13 -08001872static void *tcp_v6_tw_get_peer(struct sock *sk)
1873{
1874 struct inet_timewait_sock *tw = inet_twsk(sk);
1875
1876 if (tw->tw_family == AF_INET)
1877 return tcp_v4_tw_get_peer(sk);
1878
1879 /* Alas, not yet... */
1880 return NULL;
1881}
1882
1883static struct timewait_sock_ops tcp6_timewait_sock_ops = {
1884 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
1885 .twsk_unique = tcp_twsk_unique,
1886 .twsk_destructor= tcp_twsk_destructor,
1887 .twsk_getpeer = tcp_v6_tw_get_peer,
1888};
1889
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001890static const struct inet_connection_sock_af_ops ipv6_specific = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001891 .queue_xmit = inet6_csk_xmit,
1892 .send_check = tcp_v6_send_check,
1893 .rebuild_header = inet6_sk_rebuild_header,
1894 .conn_request = tcp_v6_conn_request,
1895 .syn_recv_sock = tcp_v6_syn_recv_sock,
David S. Miller3f419d22010-11-29 13:37:14 -08001896 .get_peer = tcp_v6_get_peer,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001897 .net_header_len = sizeof(struct ipv6hdr),
1898 .setsockopt = ipv6_setsockopt,
1899 .getsockopt = ipv6_getsockopt,
1900 .addr2sockaddr = inet6_csk_addr2sockaddr,
1901 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001902 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001903#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001904 .compat_setsockopt = compat_ipv6_setsockopt,
1905 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001906#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907};
1908
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001909#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3de2009-09-01 19:25:03 +00001910static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001911 .md5_lookup = tcp_v6_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001912 .calc_md5_hash = tcp_v6_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001913 .md5_add = tcp_v6_md5_add_func,
1914 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001915};
David S. Millera9286302006-11-14 19:53:22 -08001916#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918/*
1919 * TCP over IPv4 via INET6 API
1920 */
1921
Stephen Hemminger3b401a82009-09-01 19:25:04 +00001922static const struct inet_connection_sock_af_ops ipv6_mapped = {
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001923 .queue_xmit = ip_queue_xmit,
1924 .send_check = tcp_v4_send_check,
1925 .rebuild_header = inet_sk_rebuild_header,
1926 .conn_request = tcp_v6_conn_request,
1927 .syn_recv_sock = tcp_v6_syn_recv_sock,
David S. Miller3f419d22010-11-29 13:37:14 -08001928 .get_peer = tcp_v4_get_peer,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001929 .net_header_len = sizeof(struct iphdr),
1930 .setsockopt = ipv6_setsockopt,
1931 .getsockopt = ipv6_getsockopt,
1932 .addr2sockaddr = inet6_csk_addr2sockaddr,
1933 .sockaddr_len = sizeof(struct sockaddr_in6),
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08001934 .bind_conflict = inet6_csk_bind_conflict,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001935#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001936 .compat_setsockopt = compat_ipv6_setsockopt,
1937 .compat_getsockopt = compat_ipv6_getsockopt,
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001938#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939};
1940
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001941#ifdef CONFIG_TCP_MD5SIG
Stephen Hemmingerb2e4b3de2009-09-01 19:25:03 +00001942static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001943 .md5_lookup = tcp_v4_md5_lookup,
Adam Langley49a72df2008-07-19 00:01:42 -07001944 .calc_md5_hash = tcp_v4_md5_hash_skb,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001945 .md5_add = tcp_v6_md5_add_func,
1946 .md5_parse = tcp_v6_parse_md5_keys,
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001947};
David S. Millera9286302006-11-14 19:53:22 -08001948#endif
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950/* NOTE: A lot of things set to zero explicitly by call to
1951 * sk_alloc() so need not be done here.
1952 */
1953static int tcp_v6_init_sock(struct sock *sk)
1954{
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001955 struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 struct tcp_sock *tp = tcp_sk(sk);
1957
1958 skb_queue_head_init(&tp->out_of_order_queue);
1959 tcp_init_xmit_timers(sk);
1960 tcp_prequeue_init(tp);
1961
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001962 icsk->icsk_rto = TCP_TIMEOUT_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 tp->mdev = TCP_TIMEOUT_INIT;
1964
1965 /* So many TCP implementations out there (incorrectly) count the
1966 * initial SYN frame in their delayed-ACK and congestion control
1967 * algorithms that we must have the following bandaid to talk
1968 * efficiently to them. -DaveM
1969 */
1970 tp->snd_cwnd = 2;
1971
1972 /* See draft-stevens-tcpca-spec-01 for discussion of the
1973 * initialization of these values.
1974 */
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07001975 tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 tp->snd_cwnd_clamp = ~0;
William Allen Simpsonbee7ca92009-11-10 09:51:18 +00001977 tp->mss_cache = TCP_MSS_DEFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
1979 tp->reordering = sysctl_tcp_reordering;
1980
1981 sk->sk_state = TCP_CLOSE;
1982
Arnaldo Carvalho de Melo8292a172005-12-13 23:15:52 -08001983 icsk->icsk_af_ops = &ipv6_specific;
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03001984 icsk->icsk_ca_ops = &tcp_init_congestion_ops;
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08001985 icsk->icsk_sync_mss = tcp_sync_mss;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 sk->sk_write_space = sk_stream_write_space;
1987 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
1988
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08001989#ifdef CONFIG_TCP_MD5SIG
1990 tp->af_specific = &tcp_sock_ipv6_specific;
1991#endif
1992
William Allen Simpson435cf552009-12-02 18:17:05 +00001993 /* TCP Cookie Transactions */
1994 if (sysctl_tcp_cookie_size > 0) {
1995 /* Default, cookies without s_data_payload. */
1996 tp->cookie_values =
1997 kzalloc(sizeof(*tp->cookie_values),
1998 sk->sk_allocation);
1999 if (tp->cookie_values != NULL)
2000 kref_init(&tp->cookie_values->kref);
2001 }
2002 /* Presumed zeroed, in order of appearance:
2003 * cookie_in_always, cookie_out_never,
2004 * s_data_constant, s_data_in, s_data_out
2005 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 sk->sk_sndbuf = sysctl_tcp_wmem[1];
2007 sk->sk_rcvbuf = sysctl_tcp_rmem[1];
2008
Herbert Xueb4dea52008-12-29 23:04:08 -08002009 local_bh_disable();
Eric Dumazet17483762008-11-25 21:16:35 -08002010 percpu_counter_inc(&tcp_sockets_allocated);
Herbert Xueb4dea52008-12-29 23:04:08 -08002011 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
2013 return 0;
2014}
2015
Brian Haley7d06b2e2008-06-14 17:04:49 -07002016static void tcp_v6_destroy_sock(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017{
YOSHIFUJI Hideakicfb6eeb2006-11-14 19:07:45 -08002018#ifdef CONFIG_TCP_MD5SIG
2019 /* Clean up the MD5 key list */
2020 if (tcp_sk(sk)->md5sig_info)
2021 tcp_v6_clear_md5_list(sk);
2022#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 tcp_v4_destroy_sock(sk);
Brian Haley7d06b2e2008-06-14 17:04:49 -07002024 inet6_destroy_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025}
2026
YOSHIFUJI Hideaki952a10b2007-04-21 20:13:44 +09002027#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028/* Proc filesystem TCPv6 sock list dumping. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002029static void get_openreq6(struct seq_file *seq,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002030 struct sock *sk, struct request_sock *req, int i, int uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 int ttd = req->expires - jiffies;
Arnaldo Carvalho de Meloca304b62005-12-13 23:15:40 -08002033 struct in6_addr *src = &inet6_rsk(req)->loc_addr;
2034 struct in6_addr *dest = &inet6_rsk(req)->rmt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
2036 if (ttd < 0)
2037 ttd = 0;
2038
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 seq_printf(seq,
2040 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
2041 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
2042 i,
2043 src->s6_addr32[0], src->s6_addr32[1],
2044 src->s6_addr32[2], src->s6_addr32[3],
KOVACS Krisztianfd507032008-10-19 23:35:58 -07002045 ntohs(inet_rsk(req)->loc_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 dest->s6_addr32[0], dest->s6_addr32[1],
2047 dest->s6_addr32[2], dest->s6_addr32[3],
Arnaldo Carvalho de Melo2e6599c2005-06-18 22:46:52 -07002048 ntohs(inet_rsk(req)->rmt_port),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 TCP_SYN_RECV,
2050 0,0, /* could print option size, but that is af dependent. */
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002051 1, /* timers active (only the expire timer) */
2052 jiffies_to_clock_t(ttd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 req->retrans,
2054 uid,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002055 0, /* non standard timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 0, /* open_requests have no inode */
2057 0, req);
2058}
2059
2060static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
2061{
2062 struct in6_addr *dest, *src;
2063 __u16 destp, srcp;
2064 int timer_active;
2065 unsigned long timer_expires;
2066 struct inet_sock *inet = inet_sk(sp);
2067 struct tcp_sock *tp = tcp_sk(sp);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002068 const struct inet_connection_sock *icsk = inet_csk(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 struct ipv6_pinfo *np = inet6_sk(sp);
2070
2071 dest = &np->daddr;
2072 src = &np->rcv_saddr;
Eric Dumazetc720c7e82009-10-15 06:30:45 +00002073 destp = ntohs(inet->inet_dport);
2074 srcp = ntohs(inet->inet_sport);
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002075
2076 if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 timer_active = 1;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002078 timer_expires = icsk->icsk_timeout;
2079 } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 timer_active = 4;
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002081 timer_expires = icsk->icsk_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 } else if (timer_pending(&sp->sk_timer)) {
2083 timer_active = 2;
2084 timer_expires = sp->sk_timer.expires;
2085 } else {
2086 timer_active = 0;
2087 timer_expires = jiffies;
2088 }
2089
2090 seq_printf(seq,
2091 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
Stephen Hemminger7be87352008-06-27 20:00:19 -07002092 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 i,
2094 src->s6_addr32[0], src->s6_addr32[1],
2095 src->s6_addr32[2], src->s6_addr32[3], srcp,
2096 dest->s6_addr32[0], dest->s6_addr32[1],
2097 dest->s6_addr32[2], dest->s6_addr32[3], destp,
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002098 sp->sk_state,
Sridhar Samudrala47da8ee2006-06-27 13:29:00 -07002099 tp->write_seq-tp->snd_una,
2100 (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 timer_active,
2102 jiffies_to_clock_t(timer_expires - jiffies),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002103 icsk->icsk_retransmits,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 sock_i_uid(sp),
Arnaldo Carvalho de Melo6687e982005-08-10 04:03:31 -03002105 icsk->icsk_probes_out,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 sock_i_ino(sp),
2107 atomic_read(&sp->sk_refcnt), sp,
Stephen Hemminger7be87352008-06-27 20:00:19 -07002108 jiffies_to_clock_t(icsk->icsk_rto),
2109 jiffies_to_clock_t(icsk->icsk_ack.ato),
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002110 (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong,
Ilpo Järvinen0b6a05c2009-09-15 01:30:10 -07002111 tp->snd_cwnd,
2112 tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 );
2114}
2115
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +09002116static void get_timewait6_sock(struct seq_file *seq,
Arnaldo Carvalho de Melo8feaf0c02005-08-09 20:09:30 -07002117 struct inet_timewait_sock *tw, int i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118{
2119 struct in6_addr *dest, *src;
2120 __u16 destp, srcp;
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002121 struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 int ttd = tw->tw_ttd - jiffies;
2123
2124 if (ttd < 0)
2125 ttd = 0;
2126
Arnaldo Carvalho de Melo0fa1a532005-12-13 23:23:09 -08002127 dest = &tw6->tw_v6_daddr;
2128 src = &tw6->tw_v6_rcv_saddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 destp = ntohs(tw->tw_dport);
2130 srcp = ntohs(tw->tw_sport);
2131
2132 seq_printf(seq,
2133 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
2134 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
2135 i,
2136 src->s6_addr32[0], src->s6_addr32[1],
2137 src->s6_addr32[2], src->s6_addr32[3], srcp,
2138 dest->s6_addr32[0], dest->s6_addr32[1],
2139 dest->s6_addr32[2], dest->s6_addr32[3], destp,
2140 tw->tw_substate, 0, 0,
2141 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
2142 atomic_read(&tw->tw_refcnt), tw);
2143}
2144
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145static int tcp6_seq_show(struct seq_file *seq, void *v)
2146{
2147 struct tcp_iter_state *st;
2148
2149 if (v == SEQ_START_TOKEN) {
2150 seq_puts(seq,
2151 " sl "
2152 "local_address "
2153 "remote_address "
2154 "st tx_queue rx_queue tr tm->when retrnsmt"
2155 " uid timeout inode\n");
2156 goto out;
2157 }
2158 st = seq->private;
2159
2160 switch (st->state) {
2161 case TCP_SEQ_STATE_LISTENING:
2162 case TCP_SEQ_STATE_ESTABLISHED:
2163 get_tcp6_sock(seq, v, st->num);
2164 break;
2165 case TCP_SEQ_STATE_OPENREQ:
2166 get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);
2167 break;
2168 case TCP_SEQ_STATE_TIME_WAIT:
2169 get_timewait6_sock(seq, v, st->num);
2170 break;
2171 }
2172out:
2173 return 0;
2174}
2175
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176static struct tcp_seq_afinfo tcp6_seq_afinfo = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 .name = "tcp6",
2178 .family = AF_INET6,
Denis V. Lunev5f4472c2008-04-13 22:13:53 -07002179 .seq_fops = {
2180 .owner = THIS_MODULE,
2181 },
Denis V. Lunev9427c4b2008-04-13 22:12:13 -07002182 .seq_ops = {
2183 .show = tcp6_seq_show,
2184 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185};
2186
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002187int __net_init tcp6_proc_init(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002189 return tcp_proc_register(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190}
2191
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002192void tcp6_proc_exit(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193{
Daniel Lezcano6f8b13b2008-03-21 04:14:45 -07002194 tcp_proc_unregister(net, &tcp6_seq_afinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195}
2196#endif
2197
2198struct proto tcpv6_prot = {
2199 .name = "TCPv6",
2200 .owner = THIS_MODULE,
2201 .close = tcp_close,
2202 .connect = tcp_v6_connect,
2203 .disconnect = tcp_disconnect,
Arnaldo Carvalho de Melo463c84b2005-08-09 20:10:42 -07002204 .accept = inet_csk_accept,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 .ioctl = tcp_ioctl,
2206 .init = tcp_v6_init_sock,
2207 .destroy = tcp_v6_destroy_sock,
2208 .shutdown = tcp_shutdown,
2209 .setsockopt = tcp_setsockopt,
2210 .getsockopt = tcp_getsockopt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 .recvmsg = tcp_recvmsg,
Changli Gao7ba42912010-07-10 20:41:55 +00002212 .sendmsg = tcp_sendmsg,
2213 .sendpage = tcp_sendpage,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 .backlog_rcv = tcp_v6_do_rcv,
2215 .hash = tcp_v6_hash,
Arnaldo Carvalho de Meloab1e0a12008-02-03 04:06:04 -08002216 .unhash = inet_unhash,
2217 .get_port = inet_csk_get_port,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 .enter_memory_pressure = tcp_enter_memory_pressure,
2219 .sockets_allocated = &tcp_sockets_allocated,
2220 .memory_allocated = &tcp_memory_allocated,
2221 .memory_pressure = &tcp_memory_pressure,
Arnaldo Carvalho de Melo0a5578c2005-08-09 20:11:41 -07002222 .orphan_count = &tcp_orphan_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 .sysctl_mem = sysctl_tcp_mem,
2224 .sysctl_wmem = sysctl_tcp_wmem,
2225 .sysctl_rmem = sysctl_tcp_rmem,
2226 .max_header = MAX_TCP_HEADER,
2227 .obj_size = sizeof(struct tcp6_sock),
Eric Dumazet3ab5aee2008-11-16 19:40:17 -08002228 .slab_flags = SLAB_DESTROY_BY_RCU,
Arnaldo Carvalho de Melo6d6ee432005-12-13 23:25:19 -08002229 .twsk_prot = &tcp6_timewait_sock_ops,
Arnaldo Carvalho de Melo60236fd2005-06-18 22:47:21 -07002230 .rsk_prot = &tcp6_request_sock_ops,
Pavel Emelyanov39d8cda2008-03-22 16:50:58 -07002231 .h.hashinfo = &tcp_hashinfo,
Changli Gao7ba42912010-07-10 20:41:55 +00002232 .no_autobind = true,
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08002233#ifdef CONFIG_COMPAT
2234 .compat_setsockopt = compat_tcp_setsockopt,
2235 .compat_getsockopt = compat_tcp_getsockopt,
2236#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237};
2238
Alexey Dobriyan41135cc2009-09-14 12:22:28 +00002239static const struct inet6_protocol tcpv6_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 .handler = tcp_v6_rcv,
2241 .err_handler = tcp_v6_err,
Herbert Xua430a432006-07-08 13:34:56 -07002242 .gso_send_check = tcp_v6_gso_send_check,
Herbert Xuadcfc7d2006-06-30 13:36:15 -07002243 .gso_segment = tcp_tso_segment,
Herbert Xu684f2172009-01-08 10:41:23 -08002244 .gro_receive = tcp6_gro_receive,
2245 .gro_complete = tcp6_gro_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2247};
2248
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249static struct inet_protosw tcpv6_protosw = {
2250 .type = SOCK_STREAM,
2251 .protocol = IPPROTO_TCP,
2252 .prot = &tcpv6_prot,
2253 .ops = &inet6_stream_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 .no_check = 0,
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -08002255 .flags = INET_PROTOSW_PERMANENT |
2256 INET_PROTOSW_ICSK,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257};
2258
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002259static int __net_init tcpv6_net_init(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002260{
Denis V. Lunev56772422008-04-03 14:28:30 -07002261 return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
2262 SOCK_RAW, IPPROTO_TCP, net);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002263}
2264
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002265static void __net_exit tcpv6_net_exit(struct net *net)
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002266{
Denis V. Lunev56772422008-04-03 14:28:30 -07002267 inet_ctl_sock_destroy(net->ipv6.tcp_sk);
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002268}
2269
Alexey Dobriyan2c8c1e72010-01-17 03:35:32 +00002270static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002271{
2272 inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002273}
2274
2275static struct pernet_operations tcpv6_net_ops = {
Eric W. Biedermanb099ce22009-12-03 02:29:09 +00002276 .init = tcpv6_net_init,
2277 .exit = tcpv6_net_exit,
2278 .exit_batch = tcpv6_net_exit_batch,
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002279};
2280
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002281int __init tcpv6_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282{
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002283 int ret;
David Woodhouseae0f7d52006-01-11 15:53:04 -08002284
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002285 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2286 if (ret)
2287 goto out;
2288
2289 /* register inet6 protocol */
2290 ret = inet6_register_protosw(&tcpv6_protosw);
2291 if (ret)
2292 goto out_tcpv6_protocol;
2293
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002294 ret = register_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002295 if (ret)
2296 goto out_tcpv6_protosw;
2297out:
2298 return ret;
2299
2300out_tcpv6_protocol:
2301 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2302out_tcpv6_protosw:
2303 inet6_unregister_protosw(&tcpv6_protosw);
2304 goto out;
2305}
2306
Daniel Lezcano09f77092007-12-13 05:34:58 -08002307void tcpv6_exit(void)
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002308{
Daniel Lezcano93ec9262008-03-07 11:16:02 -08002309 unregister_pernet_subsys(&tcpv6_net_ops);
Daniel Lezcano7f4e4862007-12-11 02:25:35 -08002310 inet6_unregister_protosw(&tcpv6_protosw);
2311 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312}