aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/tcp_ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r--net/ipv6/tcp_ipv6.c101
1 files changed, 76 insertions, 25 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5f73a1808e36..c2ebbe1c5a47 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -130,6 +130,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
130 struct ipv6_pinfo *np = inet6_sk(sk); 130 struct ipv6_pinfo *np = inet6_sk(sk);
131 struct tcp_sock *tp = tcp_sk(sk); 131 struct tcp_sock *tp = tcp_sk(sk);
132 struct in6_addr *saddr = NULL, *final_p, final; 132 struct in6_addr *saddr = NULL, *final_p, final;
133 struct rt6_info *rt;
133 struct flowi fl; 134 struct flowi fl;
134 struct dst_entry *dst; 135 struct dst_entry *dst;
135 int addr_type; 136 int addr_type;
@@ -280,6 +281,26 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
280 sk->sk_gso_type = SKB_GSO_TCPV6; 281 sk->sk_gso_type = SKB_GSO_TCPV6;
281 __ip6_dst_store(sk, dst, NULL, NULL); 282 __ip6_dst_store(sk, dst, NULL, NULL);
282 283
284 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
283 icsk->icsk_ext_hdr_len = 0; 304 icsk->icsk_ext_hdr_len = 0;
284 if (np->opt) 305 if (np->opt)
285 icsk->icsk_ext_hdr_len = (np->opt->opt_flen + 306 icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
@@ -1170,6 +1191,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1170 struct ipv6_pinfo *np = inet6_sk(sk); 1191 struct ipv6_pinfo *np = inet6_sk(sk);
1171 struct tcp_sock *tp = tcp_sk(sk); 1192 struct tcp_sock *tp = tcp_sk(sk);
1172 __u32 isn = TCP_SKB_CB(skb)->when; 1193 __u32 isn = TCP_SKB_CB(skb)->when;
1194 struct dst_entry *dst = NULL;
1173#ifdef CONFIG_SYN_COOKIES 1195#ifdef CONFIG_SYN_COOKIES
1174 int want_cookie = 0; 1196 int want_cookie = 0;
1175#else 1197#else
@@ -1267,6 +1289,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1267 TCP_ECN_create_request(req, tcp_hdr(skb)); 1289 TCP_ECN_create_request(req, tcp_hdr(skb));
1268 1290
1269 if (!isn) { 1291 if (!isn) {
1292 struct inet_peer *peer = NULL;
1293
1270 if (ipv6_opt_accepted(sk, skb) || 1294 if (ipv6_opt_accepted(sk, skb) ||
1271 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || 1295 np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
1272 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { 1296 np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
@@ -1279,13 +1303,57 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1279 if (!sk->sk_bound_dev_if && 1303 if (!sk->sk_bound_dev_if &&
1280 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) 1304 ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
1281 treq->iif = inet6_iif(skb); 1305 treq->iif = inet6_iif(skb);
1282 if (!want_cookie) { 1306
1283 isn = tcp_v6_init_sequence(skb); 1307 if (want_cookie) {
1284 } else {
1285 isn = cookie_v6_init_sequence(sk, skb, &req->mss); 1308 isn = cookie_v6_init_sequence(sk, skb, &req->mss);
1286 req->cookie_ts = tmp_opt.tstamp_ok; 1309 req->cookie_ts = tmp_opt.tstamp_ok;
1310 goto have_isn;
1311 }
1312
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;
1287 } 1352 }
1353
1354 isn = tcp_v6_init_sequence(skb);
1288 } 1355 }
1356have_isn:
1289 tcp_rsk(req)->snt_isn = isn; 1357 tcp_rsk(req)->snt_isn = isn;
1290 1358
1291 security_inet_conn_request(sk, skb, req); 1359 security_inet_conn_request(sk, skb, req);
@@ -1298,6 +1366,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1298 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); 1366 inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1299 return 0; 1367 return 0;
1300 1368
1369drop_and_release:
1370 dst_release(dst);
1301drop_and_free: 1371drop_and_free:
1302 reqsk_free(req); 1372 reqsk_free(req);
1303drop: 1373drop:
@@ -1376,28 +1446,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1376 if (sk_acceptq_is_full(sk)) 1446 if (sk_acceptq_is_full(sk))
1377 goto out_overflow; 1447 goto out_overflow;
1378 1448
1379 if (dst == NULL) { 1449 if (!dst) {
1380 struct in6_addr *final_p, final; 1450 dst = inet6_csk_route_req(sk, req);
1381 struct flowi fl; 1451 if (!dst)
1382
1383 memset(&fl, 0, sizeof(fl));
1384 fl.proto = IPPROTO_TCP;
1385 ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
1386 final_p = fl6_update_dst(&fl, opt, &final);
1387 ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
1388 fl.oif = sk->sk_bound_dev_if;
1389 fl.mark = sk->sk_mark;
1390 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
1391 fl.fl_ip_sport = inet_rsk(req)->loc_port;
1392 security_req_classify_flow(req, &fl);
1393
1394 if (ip6_dst_lookup(sk, &dst, &fl))
1395 goto out;
1396
1397 if (final_p)
1398 ipv6_addr_copy(&fl.fl6_dst, final_p);
1399
1400 if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
1401 goto out; 1452 goto out;
1402 } 1453 }
1403 1454