diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 204 |
1 files changed, 56 insertions, 148 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9df64a50b075..f49476e2d884 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -277,22 +277,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 277 | rt = (struct rt6_info *) dst; | 277 | rt = (struct rt6_info *) dst; |
| 278 | if (tcp_death_row.sysctl_tw_recycle && | 278 | if (tcp_death_row.sysctl_tw_recycle && |
| 279 | !tp->rx_opt.ts_recent_stamp && | 279 | !tp->rx_opt.ts_recent_stamp && |
| 280 | ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) { | 280 | ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) |
| 281 | struct inet_peer *peer = rt6_get_peer(rt); | 281 | tcp_fetch_timewait_stamp(sk, dst); |
| 282 | /* | ||
| 283 | * VJ's idea. We save last timestamp seen from | ||
| 284 | * the destination in peer table, when entering state | ||
| 285 | * TIME-WAIT * and initialize rx_opt.ts_recent from it, | ||
| 286 | * when trying new connection. | ||
| 287 | */ | ||
| 288 | if (peer) { | ||
| 289 | inet_peer_refcheck(peer); | ||
| 290 | if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) { | ||
| 291 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; | ||
| 292 | tp->rx_opt.ts_recent = peer->tcp_ts; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } | ||
| 296 | 282 | ||
| 297 | icsk->icsk_ext_hdr_len = 0; | 283 | icsk->icsk_ext_hdr_len = 0; |
| 298 | if (np->opt) | 284 | if (np->opt) |
| @@ -329,6 +315,23 @@ failure: | |||
| 329 | return err; | 315 | return err; |
| 330 | } | 316 | } |
| 331 | 317 | ||
| 318 | static void tcp_v6_mtu_reduced(struct sock *sk) | ||
| 319 | { | ||
| 320 | struct dst_entry *dst; | ||
| 321 | |||
| 322 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) | ||
| 323 | return; | ||
| 324 | |||
| 325 | dst = inet6_csk_update_pmtu(sk, tcp_sk(sk)->mtu_info); | ||
| 326 | if (!dst) | ||
| 327 | return; | ||
| 328 | |||
| 329 | if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { | ||
| 330 | tcp_sync_mss(sk, dst_mtu(dst)); | ||
| 331 | tcp_simple_retransmit(sk); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 332 | static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 335 | static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 333 | u8 type, u8 code, int offset, __be32 info) | 336 | u8 type, u8 code, int offset, __be32 info) |
| 334 | { | 337 | { |
| @@ -356,7 +359,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 356 | } | 359 | } |
| 357 | 360 | ||
| 358 | bh_lock_sock(sk); | 361 | bh_lock_sock(sk); |
| 359 | if (sock_owned_by_user(sk)) | 362 | if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) |
| 360 | NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); | 363 | NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); |
| 361 | 364 | ||
| 362 | if (sk->sk_state == TCP_CLOSE) | 365 | if (sk->sk_state == TCP_CLOSE) |
| @@ -377,49 +380,19 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 377 | 380 | ||
| 378 | np = inet6_sk(sk); | 381 | np = inet6_sk(sk); |
| 379 | 382 | ||
| 380 | if (type == ICMPV6_PKT_TOOBIG) { | 383 | if (type == NDISC_REDIRECT) { |
| 381 | struct dst_entry *dst; | 384 | struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); |
| 382 | |||
| 383 | if (sock_owned_by_user(sk)) | ||
| 384 | goto out; | ||
| 385 | if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) | ||
| 386 | goto out; | ||
| 387 | |||
| 388 | /* icmp should have updated the destination cache entry */ | ||
| 389 | dst = __sk_dst_check(sk, np->dst_cookie); | ||
| 390 | |||
| 391 | if (dst == NULL) { | ||
| 392 | struct inet_sock *inet = inet_sk(sk); | ||
| 393 | struct flowi6 fl6; | ||
| 394 | |||
| 395 | /* BUGGG_FUTURE: Again, it is not clear how | ||
| 396 | to handle rthdr case. Ignore this complexity | ||
| 397 | for now. | ||
| 398 | */ | ||
| 399 | memset(&fl6, 0, sizeof(fl6)); | ||
| 400 | fl6.flowi6_proto = IPPROTO_TCP; | ||
| 401 | fl6.daddr = np->daddr; | ||
| 402 | fl6.saddr = np->saddr; | ||
| 403 | fl6.flowi6_oif = sk->sk_bound_dev_if; | ||
| 404 | fl6.flowi6_mark = sk->sk_mark; | ||
| 405 | fl6.fl6_dport = inet->inet_dport; | ||
| 406 | fl6.fl6_sport = inet->inet_sport; | ||
| 407 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); | ||
| 408 | |||
| 409 | dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false); | ||
| 410 | if (IS_ERR(dst)) { | ||
| 411 | sk->sk_err_soft = -PTR_ERR(dst); | ||
| 412 | goto out; | ||
| 413 | } | ||
| 414 | 385 | ||
| 415 | } else | 386 | if (dst) |
| 416 | dst_hold(dst); | 387 | dst->ops->redirect(dst, sk, skb); |
| 388 | } | ||
| 417 | 389 | ||
| 418 | if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { | 390 | if (type == ICMPV6_PKT_TOOBIG) { |
| 419 | tcp_sync_mss(sk, dst_mtu(dst)); | 391 | tp->mtu_info = ntohl(info); |
| 420 | tcp_simple_retransmit(sk); | 392 | if (!sock_owned_by_user(sk)) |
| 421 | } /* else let the usual retransmit timer handle it */ | 393 | tcp_v6_mtu_reduced(sk); |
| 422 | dst_release(dst); | 394 | else |
| 395 | set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags); | ||
| 423 | goto out; | 396 | goto out; |
| 424 | } | 397 | } |
| 425 | 398 | ||
| @@ -475,62 +448,43 @@ out: | |||
| 475 | } | 448 | } |
| 476 | 449 | ||
| 477 | 450 | ||
| 478 | static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | 451 | static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, |
| 452 | struct flowi6 *fl6, | ||
| 453 | struct request_sock *req, | ||
| 479 | struct request_values *rvp, | 454 | struct request_values *rvp, |
| 480 | u16 queue_mapping) | 455 | u16 queue_mapping) |
| 481 | { | 456 | { |
| 482 | struct inet6_request_sock *treq = inet6_rsk(req); | 457 | struct inet6_request_sock *treq = inet6_rsk(req); |
| 483 | struct ipv6_pinfo *np = inet6_sk(sk); | 458 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 484 | struct sk_buff * skb; | 459 | struct sk_buff * skb; |
| 485 | struct ipv6_txoptions *opt = NULL; | 460 | int err = -ENOMEM; |
| 486 | struct in6_addr * final_p, final; | ||
| 487 | struct flowi6 fl6; | ||
| 488 | struct dst_entry *dst; | ||
| 489 | int err; | ||
| 490 | 461 | ||
| 491 | memset(&fl6, 0, sizeof(fl6)); | 462 | /* First, grab a route. */ |
| 492 | fl6.flowi6_proto = IPPROTO_TCP; | 463 | if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL) |
| 493 | fl6.daddr = treq->rmt_addr; | ||
| 494 | fl6.saddr = treq->loc_addr; | ||
| 495 | fl6.flowlabel = 0; | ||
| 496 | fl6.flowi6_oif = treq->iif; | ||
| 497 | fl6.flowi6_mark = sk->sk_mark; | ||
| 498 | fl6.fl6_dport = inet_rsk(req)->rmt_port; | ||
| 499 | fl6.fl6_sport = inet_rsk(req)->loc_port; | ||
| 500 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); | ||
| 501 | |||
| 502 | opt = np->opt; | ||
| 503 | final_p = fl6_update_dst(&fl6, opt, &final); | ||
| 504 | |||
| 505 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); | ||
| 506 | if (IS_ERR(dst)) { | ||
| 507 | err = PTR_ERR(dst); | ||
| 508 | dst = NULL; | ||
| 509 | goto done; | 464 | goto done; |
| 510 | } | 465 | |
| 511 | skb = tcp_make_synack(sk, dst, req, rvp); | 466 | skb = tcp_make_synack(sk, dst, req, rvp); |
| 512 | err = -ENOMEM; | 467 | |
| 513 | if (skb) { | 468 | if (skb) { |
| 514 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); | 469 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); |
| 515 | 470 | ||
| 516 | fl6.daddr = treq->rmt_addr; | 471 | fl6->daddr = treq->rmt_addr; |
| 517 | skb_set_queue_mapping(skb, queue_mapping); | 472 | skb_set_queue_mapping(skb, queue_mapping); |
| 518 | err = ip6_xmit(sk, skb, &fl6, opt, np->tclass); | 473 | err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); |
| 519 | err = net_xmit_eval(err); | 474 | err = net_xmit_eval(err); |
| 520 | } | 475 | } |
| 521 | 476 | ||
| 522 | done: | 477 | done: |
| 523 | if (opt && opt != np->opt) | ||
| 524 | sock_kfree_s(sk, opt, opt->tot_len); | ||
| 525 | dst_release(dst); | ||
| 526 | return err; | 478 | return err; |
| 527 | } | 479 | } |
| 528 | 480 | ||
| 529 | static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, | 481 | static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, |
| 530 | struct request_values *rvp) | 482 | struct request_values *rvp) |
| 531 | { | 483 | { |
| 484 | struct flowi6 fl6; | ||
| 485 | |||
| 532 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | 486 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); |
| 533 | return tcp_v6_send_synack(sk, req, rvp, 0); | 487 | return tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0); |
| 534 | } | 488 | } |
| 535 | 489 | ||
| 536 | static void tcp_v6_reqsk_destructor(struct request_sock *req) | 490 | static void tcp_v6_reqsk_destructor(struct request_sock *req) |
| @@ -1057,6 +1011,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1057 | struct tcp_sock *tp = tcp_sk(sk); | 1011 | struct tcp_sock *tp = tcp_sk(sk); |
| 1058 | __u32 isn = TCP_SKB_CB(skb)->when; | 1012 | __u32 isn = TCP_SKB_CB(skb)->when; |
| 1059 | struct dst_entry *dst = NULL; | 1013 | struct dst_entry *dst = NULL; |
| 1014 | struct flowi6 fl6; | ||
| 1060 | bool want_cookie = false; | 1015 | bool want_cookie = false; |
| 1061 | 1016 | ||
| 1062 | if (skb->protocol == htons(ETH_P_IP)) | 1017 | if (skb->protocol == htons(ETH_P_IP)) |
| @@ -1085,7 +1040,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1085 | tcp_clear_options(&tmp_opt); | 1040 | tcp_clear_options(&tmp_opt); |
| 1086 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); | 1041 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); |
| 1087 | tmp_opt.user_mss = tp->rx_opt.user_mss; | 1042 | tmp_opt.user_mss = tp->rx_opt.user_mss; |
| 1088 | tcp_parse_options(skb, &tmp_opt, &hash_location, 0); | 1043 | tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL); |
| 1089 | 1044 | ||
| 1090 | if (tmp_opt.cookie_plus > 0 && | 1045 | if (tmp_opt.cookie_plus > 0 && |
| 1091 | tmp_opt.saw_tstamp && | 1046 | tmp_opt.saw_tstamp && |
| @@ -1150,8 +1105,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1150 | treq->iif = inet6_iif(skb); | 1105 | treq->iif = inet6_iif(skb); |
| 1151 | 1106 | ||
| 1152 | if (!isn) { | 1107 | if (!isn) { |
| 1153 | struct inet_peer *peer = NULL; | ||
| 1154 | |||
| 1155 | if (ipv6_opt_accepted(sk, skb) || | 1108 | if (ipv6_opt_accepted(sk, skb) || |
| 1156 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1109 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
| 1157 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1110 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
| @@ -1176,14 +1129,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1176 | */ | 1129 | */ |
| 1177 | if (tmp_opt.saw_tstamp && | 1130 | if (tmp_opt.saw_tstamp && |
| 1178 | tcp_death_row.sysctl_tw_recycle && | 1131 | tcp_death_row.sysctl_tw_recycle && |
| 1179 | (dst = inet6_csk_route_req(sk, req)) != NULL && | 1132 | (dst = inet6_csk_route_req(sk, &fl6, req)) != NULL) { |
| 1180 | (peer = rt6_get_peer((struct rt6_info *)dst)) != NULL && | 1133 | if (!tcp_peer_is_proven(req, dst, true)) { |
| 1181 | ipv6_addr_equal((struct in6_addr *)peer->daddr.addr.a6, | ||
| 1182 | &treq->rmt_addr)) { | ||
| 1183 | inet_peer_refcheck(peer); | ||
| 1184 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && | ||
| 1185 | (s32)(peer->tcp_ts - req->ts_recent) > | ||
| 1186 | TCP_PAWS_WINDOW) { | ||
| 1187 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | 1134 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); |
| 1188 | goto drop_and_release; | 1135 | goto drop_and_release; |
| 1189 | } | 1136 | } |
| @@ -1192,8 +1139,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1192 | else if (!sysctl_tcp_syncookies && | 1139 | else if (!sysctl_tcp_syncookies && |
| 1193 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | 1140 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < |
| 1194 | (sysctl_max_syn_backlog >> 2)) && | 1141 | (sysctl_max_syn_backlog >> 2)) && |
| 1195 | (!peer || !peer->tcp_ts_stamp) && | 1142 | !tcp_peer_is_proven(req, dst, false)) { |
| 1196 | (!dst || !dst_metric(dst, RTAX_RTT))) { | ||
| 1197 | /* Without syncookies last quarter of | 1143 | /* Without syncookies last quarter of |
| 1198 | * backlog is filled with destinations, | 1144 | * backlog is filled with destinations, |
| 1199 | * proven to be alive. | 1145 | * proven to be alive. |
| @@ -1215,7 +1161,7 @@ have_isn: | |||
| 1215 | if (security_inet_conn_request(sk, skb, req)) | 1161 | if (security_inet_conn_request(sk, skb, req)) |
| 1216 | goto drop_and_release; | 1162 | goto drop_and_release; |
| 1217 | 1163 | ||
| 1218 | if (tcp_v6_send_synack(sk, req, | 1164 | if (tcp_v6_send_synack(sk, dst, &fl6, req, |
| 1219 | (struct request_values *)&tmp_ext, | 1165 | (struct request_values *)&tmp_ext, |
| 1220 | skb_get_queue_mapping(skb)) || | 1166 | skb_get_queue_mapping(skb)) || |
| 1221 | want_cookie) | 1167 | want_cookie) |
| @@ -1242,10 +1188,10 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1242 | struct inet_sock *newinet; | 1188 | struct inet_sock *newinet; |
| 1243 | struct tcp_sock *newtp; | 1189 | struct tcp_sock *newtp; |
| 1244 | struct sock *newsk; | 1190 | struct sock *newsk; |
| 1245 | struct ipv6_txoptions *opt; | ||
| 1246 | #ifdef CONFIG_TCP_MD5SIG | 1191 | #ifdef CONFIG_TCP_MD5SIG |
| 1247 | struct tcp_md5sig_key *key; | 1192 | struct tcp_md5sig_key *key; |
| 1248 | #endif | 1193 | #endif |
| 1194 | struct flowi6 fl6; | ||
| 1249 | 1195 | ||
| 1250 | if (skb->protocol == htons(ETH_P_IP)) { | 1196 | if (skb->protocol == htons(ETH_P_IP)) { |
| 1251 | /* | 1197 | /* |
| @@ -1302,13 +1248,12 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1302 | } | 1248 | } |
| 1303 | 1249 | ||
| 1304 | treq = inet6_rsk(req); | 1250 | treq = inet6_rsk(req); |
| 1305 | opt = np->opt; | ||
| 1306 | 1251 | ||
| 1307 | if (sk_acceptq_is_full(sk)) | 1252 | if (sk_acceptq_is_full(sk)) |
| 1308 | goto out_overflow; | 1253 | goto out_overflow; |
| 1309 | 1254 | ||
| 1310 | if (!dst) { | 1255 | if (!dst) { |
| 1311 | dst = inet6_csk_route_req(sk, req); | 1256 | dst = inet6_csk_route_req(sk, &fl6, req); |
| 1312 | if (!dst) | 1257 | if (!dst) |
| 1313 | goto out; | 1258 | goto out; |
| 1314 | } | 1259 | } |
| @@ -1371,11 +1316,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1371 | but we make one more one thing there: reattach optmem | 1316 | but we make one more one thing there: reattach optmem |
| 1372 | to newsk. | 1317 | to newsk. |
| 1373 | */ | 1318 | */ |
| 1374 | if (opt) { | 1319 | if (np->opt) |
| 1375 | newnp->opt = ipv6_dup_options(newsk, opt); | 1320 | newnp->opt = ipv6_dup_options(newsk, np->opt); |
| 1376 | if (opt != np->opt) | ||
| 1377 | sock_kfree_s(sk, opt, opt->tot_len); | ||
| 1378 | } | ||
| 1379 | 1321 | ||
| 1380 | inet_csk(newsk)->icsk_ext_hdr_len = 0; | 1322 | inet_csk(newsk)->icsk_ext_hdr_len = 0; |
| 1381 | if (newnp->opt) | 1323 | if (newnp->opt) |
| @@ -1422,8 +1364,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1422 | out_overflow: | 1364 | out_overflow: |
| 1423 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | 1365 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); |
| 1424 | out_nonewsk: | 1366 | out_nonewsk: |
| 1425 | if (opt && opt != np->opt) | ||
| 1426 | sock_kfree_s(sk, opt, opt->tot_len); | ||
| 1427 | dst_release(dst); | 1367 | dst_release(dst); |
| 1428 | out: | 1368 | out: |
| 1429 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | 1369 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); |
| @@ -1734,42 +1674,10 @@ do_time_wait: | |||
| 1734 | goto discard_it; | 1674 | goto discard_it; |
| 1735 | } | 1675 | } |
| 1736 | 1676 | ||
| 1737 | static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it) | ||
| 1738 | { | ||
| 1739 | struct rt6_info *rt = (struct rt6_info *) __sk_dst_get(sk); | ||
| 1740 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 1741 | struct inet_peer *peer; | ||
| 1742 | |||
| 1743 | if (!rt || | ||
| 1744 | !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr)) { | ||
| 1745 | peer = inet_getpeer_v6(&np->daddr, 1); | ||
| 1746 | *release_it = true; | ||
| 1747 | } else { | ||
| 1748 | if (!rt->rt6i_peer) | ||
| 1749 | rt6_bind_peer(rt, 1); | ||
| 1750 | peer = rt->rt6i_peer; | ||
| 1751 | *release_it = false; | ||
| 1752 | } | ||
| 1753 | |||
| 1754 | return peer; | ||
| 1755 | } | ||
| 1756 | |||
| 1757 | static void *tcp_v6_tw_get_peer(struct sock *sk) | ||
| 1758 | { | ||
| 1759 | const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); | ||
| 1760 | const struct inet_timewait_sock *tw = inet_twsk(sk); | ||
| 1761 | |||
| 1762 | if (tw->tw_family == AF_INET) | ||
| 1763 | return tcp_v4_tw_get_peer(sk); | ||
| 1764 | |||
| 1765 | return inet_getpeer_v6(&tw6->tw_v6_daddr, 1); | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | 1677 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { |
| 1769 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | 1678 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), |
| 1770 | .twsk_unique = tcp_twsk_unique, | 1679 | .twsk_unique = tcp_twsk_unique, |
| 1771 | .twsk_destructor= tcp_twsk_destructor, | 1680 | .twsk_destructor= tcp_twsk_destructor, |
| 1772 | .twsk_getpeer = tcp_v6_tw_get_peer, | ||
| 1773 | }; | 1681 | }; |
| 1774 | 1682 | ||
| 1775 | static const struct inet_connection_sock_af_ops ipv6_specific = { | 1683 | static const struct inet_connection_sock_af_ops ipv6_specific = { |
| @@ -1778,7 +1686,6 @@ static const struct inet_connection_sock_af_ops ipv6_specific = { | |||
| 1778 | .rebuild_header = inet6_sk_rebuild_header, | 1686 | .rebuild_header = inet6_sk_rebuild_header, |
| 1779 | .conn_request = tcp_v6_conn_request, | 1687 | .conn_request = tcp_v6_conn_request, |
| 1780 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1688 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
| 1781 | .get_peer = tcp_v6_get_peer, | ||
| 1782 | .net_header_len = sizeof(struct ipv6hdr), | 1689 | .net_header_len = sizeof(struct ipv6hdr), |
| 1783 | .net_frag_header_len = sizeof(struct frag_hdr), | 1690 | .net_frag_header_len = sizeof(struct frag_hdr), |
| 1784 | .setsockopt = ipv6_setsockopt, | 1691 | .setsockopt = ipv6_setsockopt, |
| @@ -1810,7 +1717,6 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
| 1810 | .rebuild_header = inet_sk_rebuild_header, | 1717 | .rebuild_header = inet_sk_rebuild_header, |
| 1811 | .conn_request = tcp_v6_conn_request, | 1718 | .conn_request = tcp_v6_conn_request, |
| 1812 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1719 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
| 1813 | .get_peer = tcp_v4_get_peer, | ||
| 1814 | .net_header_len = sizeof(struct iphdr), | 1720 | .net_header_len = sizeof(struct iphdr), |
| 1815 | .setsockopt = ipv6_setsockopt, | 1721 | .setsockopt = ipv6_setsockopt, |
| 1816 | .getsockopt = ipv6_getsockopt, | 1722 | .getsockopt = ipv6_getsockopt, |
| @@ -2049,6 +1955,8 @@ struct proto tcpv6_prot = { | |||
| 2049 | .sendmsg = tcp_sendmsg, | 1955 | .sendmsg = tcp_sendmsg, |
| 2050 | .sendpage = tcp_sendpage, | 1956 | .sendpage = tcp_sendpage, |
| 2051 | .backlog_rcv = tcp_v6_do_rcv, | 1957 | .backlog_rcv = tcp_v6_do_rcv, |
| 1958 | .release_cb = tcp_release_cb, | ||
| 1959 | .mtu_reduced = tcp_v6_mtu_reduced, | ||
| 2052 | .hash = tcp_v6_hash, | 1960 | .hash = tcp_v6_hash, |
| 2053 | .unhash = inet_unhash, | 1961 | .unhash = inet_unhash, |
| 2054 | .get_port = inet_csk_get_port, | 1962 | .get_port = inet_csk_get_port, |
