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.c56
1 files changed, 35 insertions, 21 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 44d431849d39..eec814fe53b8 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -90,6 +90,17 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk,
90} 90}
91#endif 91#endif
92 92
93/* Helper returning the inet6 address from a given tcp socket.
94 * It can be used in TCP stack instead of inet6_sk(sk).
95 * This avoids a dereference and allow compiler optimizations.
96 */
97static struct ipv6_pinfo *tcp_inet6_sk(const struct sock *sk)
98{
99 struct tcp6_sock *tcp6 = container_of(tcp_sk(sk), struct tcp6_sock, tcp);
100
101 return &tcp6->inet6;
102}
103
93static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) 104static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
94{ 105{
95 struct dst_entry *dst = skb_dst(skb); 106 struct dst_entry *dst = skb_dst(skb);
@@ -99,7 +110,7 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
99 110
100 sk->sk_rx_dst = dst; 111 sk->sk_rx_dst = dst;
101 inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; 112 inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
102 inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt); 113 tcp_inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt);
103 } 114 }
104} 115}
105 116
@@ -138,7 +149,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
138 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; 149 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
139 struct inet_sock *inet = inet_sk(sk); 150 struct inet_sock *inet = inet_sk(sk);
140 struct inet_connection_sock *icsk = inet_csk(sk); 151 struct inet_connection_sock *icsk = inet_csk(sk);
141 struct ipv6_pinfo *np = inet6_sk(sk); 152 struct ipv6_pinfo *np = tcp_inet6_sk(sk);
142 struct tcp_sock *tp = tcp_sk(sk); 153 struct tcp_sock *tp = tcp_sk(sk);
143 struct in6_addr *saddr = NULL, *final_p, final; 154 struct in6_addr *saddr = NULL, *final_p, final;
144 struct ipv6_txoptions *opt; 155 struct ipv6_txoptions *opt;
@@ -390,7 +401,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
390 if (sk->sk_state == TCP_CLOSE) 401 if (sk->sk_state == TCP_CLOSE)
391 goto out; 402 goto out;
392 403
393 if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) { 404 if (ipv6_hdr(skb)->hop_limit < tcp_inet6_sk(sk)->min_hopcount) {
394 __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 405 __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP);
395 goto out; 406 goto out;
396 } 407 }
@@ -405,7 +416,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
405 goto out; 416 goto out;
406 } 417 }
407 418
408 np = inet6_sk(sk); 419 np = tcp_inet6_sk(sk);
409 420
410 if (type == NDISC_REDIRECT) { 421 if (type == NDISC_REDIRECT) {
411 if (!sock_owned_by_user(sk)) { 422 if (!sock_owned_by_user(sk)) {
@@ -478,7 +489,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
478 enum tcp_synack_type synack_type) 489 enum tcp_synack_type synack_type)
479{ 490{
480 struct inet_request_sock *ireq = inet_rsk(req); 491 struct inet_request_sock *ireq = inet_rsk(req);
481 struct ipv6_pinfo *np = inet6_sk(sk); 492 struct ipv6_pinfo *np = tcp_inet6_sk(sk);
482 struct ipv6_txoptions *opt; 493 struct ipv6_txoptions *opt;
483 struct flowi6 *fl6 = &fl->u.ip6; 494 struct flowi6 *fl6 = &fl->u.ip6;
484 struct sk_buff *skb; 495 struct sk_buff *skb;
@@ -737,7 +748,7 @@ static void tcp_v6_init_req(struct request_sock *req,
737{ 748{
738 bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); 749 bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags);
739 struct inet_request_sock *ireq = inet_rsk(req); 750 struct inet_request_sock *ireq = inet_rsk(req);
740 const struct ipv6_pinfo *np = inet6_sk(sk_listener); 751 const struct ipv6_pinfo *np = tcp_inet6_sk(sk_listener);
741 752
742 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; 753 ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
743 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; 754 ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
@@ -1066,9 +1077,8 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
1066{ 1077{
1067 struct inet_request_sock *ireq; 1078 struct inet_request_sock *ireq;
1068 struct ipv6_pinfo *newnp; 1079 struct ipv6_pinfo *newnp;
1069 const struct ipv6_pinfo *np = inet6_sk(sk); 1080 const struct ipv6_pinfo *np = tcp_inet6_sk(sk);
1070 struct ipv6_txoptions *opt; 1081 struct ipv6_txoptions *opt;
1071 struct tcp6_sock *newtcp6sk;
1072 struct inet_sock *newinet; 1082 struct inet_sock *newinet;
1073 struct tcp_sock *newtp; 1083 struct tcp_sock *newtp;
1074 struct sock *newsk; 1084 struct sock *newsk;
@@ -1088,11 +1098,10 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
1088 if (!newsk) 1098 if (!newsk)
1089 return NULL; 1099 return NULL;
1090 1100
1091 newtcp6sk = (struct tcp6_sock *)newsk; 1101 inet_sk(newsk)->pinet6 = tcp_inet6_sk(newsk);
1092 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1093 1102
1094 newinet = inet_sk(newsk); 1103 newinet = inet_sk(newsk);
1095 newnp = inet6_sk(newsk); 1104 newnp = tcp_inet6_sk(newsk);
1096 newtp = tcp_sk(newsk); 1105 newtp = tcp_sk(newsk);
1097 1106
1098 memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 1107 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
@@ -1156,12 +1165,11 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
1156 ip6_dst_store(newsk, dst, NULL, NULL); 1165 ip6_dst_store(newsk, dst, NULL, NULL);
1157 inet6_sk_rx_dst_set(newsk, skb); 1166 inet6_sk_rx_dst_set(newsk, skb);
1158 1167
1159 newtcp6sk = (struct tcp6_sock *)newsk; 1168 inet_sk(newsk)->pinet6 = tcp_inet6_sk(newsk);
1160 inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
1161 1169
1162 newtp = tcp_sk(newsk); 1170 newtp = tcp_sk(newsk);
1163 newinet = inet_sk(newsk); 1171 newinet = inet_sk(newsk);
1164 newnp = inet6_sk(newsk); 1172 newnp = tcp_inet6_sk(newsk);
1165 1173
1166 memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 1174 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
1167 1175
@@ -1276,9 +1284,9 @@ out:
1276 */ 1284 */
1277static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) 1285static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
1278{ 1286{
1279 struct ipv6_pinfo *np = inet6_sk(sk); 1287 struct ipv6_pinfo *np = tcp_inet6_sk(sk);
1280 struct tcp_sock *tp;
1281 struct sk_buff *opt_skb = NULL; 1288 struct sk_buff *opt_skb = NULL;
1289 struct tcp_sock *tp;
1282 1290
1283 /* Imagine: socket is IPv6. IPv4 packet arrives, 1291 /* Imagine: socket is IPv6. IPv4 packet arrives,
1284 goes to IPv4 receive handler and backlogged. 1292 goes to IPv4 receive handler and backlogged.
@@ -1428,6 +1436,7 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
1428 1436
1429static int tcp_v6_rcv(struct sk_buff *skb) 1437static int tcp_v6_rcv(struct sk_buff *skb)
1430{ 1438{
1439 struct sk_buff *skb_to_free;
1431 int sdif = inet6_sdif(skb); 1440 int sdif = inet6_sdif(skb);
1432 const struct tcphdr *th; 1441 const struct tcphdr *th;
1433 const struct ipv6hdr *hdr; 1442 const struct ipv6hdr *hdr;
@@ -1524,7 +1533,7 @@ process:
1524 return 0; 1533 return 0;
1525 } 1534 }
1526 } 1535 }
1527 if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { 1536 if (hdr->hop_limit < tcp_inet6_sk(sk)->min_hopcount) {
1528 __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 1537 __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP);
1529 goto discard_and_relse; 1538 goto discard_and_relse;
1530 } 1539 }
@@ -1554,12 +1563,17 @@ process:
1554 tcp_segs_in(tcp_sk(sk), skb); 1563 tcp_segs_in(tcp_sk(sk), skb);
1555 ret = 0; 1564 ret = 0;
1556 if (!sock_owned_by_user(sk)) { 1565 if (!sock_owned_by_user(sk)) {
1566 skb_to_free = sk->sk_rx_skb_cache;
1567 sk->sk_rx_skb_cache = NULL;
1557 ret = tcp_v6_do_rcv(sk, skb); 1568 ret = tcp_v6_do_rcv(sk, skb);
1558 } else if (tcp_add_backlog(sk, skb)) { 1569 } else {
1559 goto discard_and_relse; 1570 if (tcp_add_backlog(sk, skb))
1571 goto discard_and_relse;
1572 skb_to_free = NULL;
1560 } 1573 }
1561 bh_unlock_sock(sk); 1574 bh_unlock_sock(sk);
1562 1575 if (skb_to_free)
1576 __kfree_skb(skb_to_free);
1563put_and_return: 1577put_and_return:
1564 if (refcounted) 1578 if (refcounted)
1565 sock_put(sk); 1579 sock_put(sk);
@@ -1669,7 +1683,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
1669 struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst); 1683 struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst);
1670 1684
1671 if (dst) 1685 if (dst)
1672 dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); 1686 dst = dst_check(dst, tcp_inet6_sk(sk)->rx_dst_cookie);
1673 if (dst && 1687 if (dst &&
1674 inet_sk(sk)->rx_dst_ifindex == skb->skb_iif) 1688 inet_sk(sk)->rx_dst_ifindex == skb->skb_iif)
1675 skb_dst_set_noref(skb, dst); 1689 skb_dst_set_noref(skb, dst);