diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 56 |
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 | */ | ||
97 | static 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 | |||
93 | static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) | 104 | static 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 | */ |
1277 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | 1285 | static 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 | ||
1429 | static int tcp_v6_rcv(struct sk_buff *skb) | 1437 | static 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); | ||
1563 | put_and_return: | 1577 | put_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); |