diff options
-rw-r--r-- | net/ipv6/datagram.c | 21 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.c | 38 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.h | 3 |
3 files changed, 32 insertions, 30 deletions
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index fbf08ce3f5ab..8a9ac2d0f5d3 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -146,10 +146,12 @@ int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, | |||
146 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; | 146 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; |
147 | struct inet_sock *inet = inet_sk(sk); | 147 | struct inet_sock *inet = inet_sk(sk); |
148 | struct ipv6_pinfo *np = inet6_sk(sk); | 148 | struct ipv6_pinfo *np = inet6_sk(sk); |
149 | struct in6_addr *daddr; | 149 | struct in6_addr *daddr, old_daddr; |
150 | __be32 fl6_flowlabel = 0; | ||
151 | __be32 old_fl6_flowlabel; | ||
152 | __be32 old_dport; | ||
150 | int addr_type; | 153 | int addr_type; |
151 | int err; | 154 | int err; |
152 | __be32 fl6_flowlabel = 0; | ||
153 | 155 | ||
154 | if (usin->sin6_family == AF_INET) { | 156 | if (usin->sin6_family == AF_INET) { |
155 | if (__ipv6_only_sock(sk)) | 157 | if (__ipv6_only_sock(sk)) |
@@ -238,9 +240,13 @@ ipv4_connected: | |||
238 | } | 240 | } |
239 | } | 241 | } |
240 | 242 | ||
243 | /* save the current peer information before updating it */ | ||
244 | old_daddr = sk->sk_v6_daddr; | ||
245 | old_fl6_flowlabel = np->flow_label; | ||
246 | old_dport = inet->inet_dport; | ||
247 | |||
241 | sk->sk_v6_daddr = *daddr; | 248 | sk->sk_v6_daddr = *daddr; |
242 | np->flow_label = fl6_flowlabel; | 249 | np->flow_label = fl6_flowlabel; |
243 | |||
244 | inet->inet_dport = usin->sin6_port; | 250 | inet->inet_dport = usin->sin6_port; |
245 | 251 | ||
246 | /* | 252 | /* |
@@ -250,11 +256,12 @@ ipv4_connected: | |||
250 | 256 | ||
251 | err = ip6_datagram_dst_update(sk, true); | 257 | err = ip6_datagram_dst_update(sk, true); |
252 | if (err) { | 258 | if (err) { |
253 | /* Reset daddr and dport so that udp_v6_early_demux() | 259 | /* Restore the socket peer info, to keep it consistent with |
254 | * fails to find this socket | 260 | * the old socket state |
255 | */ | 261 | */ |
256 | memset(&sk->sk_v6_daddr, 0, sizeof(sk->sk_v6_daddr)); | 262 | sk->sk_v6_daddr = old_daddr; |
257 | inet->inet_dport = 0; | 263 | np->flow_label = old_fl6_flowlabel; |
264 | inet->inet_dport = old_dport; | ||
258 | goto out; | 265 | goto out; |
259 | } | 266 | } |
260 | 267 | ||
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index e22512e32827..14b67dfacc4b 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -111,6 +111,13 @@ struct l2tp_net { | |||
111 | spinlock_t l2tp_session_hlist_lock; | 111 | spinlock_t l2tp_session_hlist_lock; |
112 | }; | 112 | }; |
113 | 113 | ||
114 | #if IS_ENABLED(CONFIG_IPV6) | ||
115 | static bool l2tp_sk_is_v6(struct sock *sk) | ||
116 | { | ||
117 | return sk->sk_family == PF_INET6 && | ||
118 | !ipv6_addr_v4mapped(&sk->sk_v6_daddr); | ||
119 | } | ||
120 | #endif | ||
114 | 121 | ||
115 | static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) | 122 | static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) |
116 | { | 123 | { |
@@ -1049,7 +1056,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, | |||
1049 | /* Queue the packet to IP for output */ | 1056 | /* Queue the packet to IP for output */ |
1050 | skb->ignore_df = 1; | 1057 | skb->ignore_df = 1; |
1051 | #if IS_ENABLED(CONFIG_IPV6) | 1058 | #if IS_ENABLED(CONFIG_IPV6) |
1052 | if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped) | 1059 | if (l2tp_sk_is_v6(tunnel->sock)) |
1053 | error = inet6_csk_xmit(tunnel->sock, skb, NULL); | 1060 | error = inet6_csk_xmit(tunnel->sock, skb, NULL); |
1054 | else | 1061 | else |
1055 | #endif | 1062 | #endif |
@@ -1112,6 +1119,15 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len | |||
1112 | goto out_unlock; | 1119 | goto out_unlock; |
1113 | } | 1120 | } |
1114 | 1121 | ||
1122 | /* The user-space may change the connection status for the user-space | ||
1123 | * provided socket at run time: we must check it under the socket lock | ||
1124 | */ | ||
1125 | if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) { | ||
1126 | kfree_skb(skb); | ||
1127 | ret = NET_XMIT_DROP; | ||
1128 | goto out_unlock; | ||
1129 | } | ||
1130 | |||
1115 | /* Get routing info from the tunnel socket */ | 1131 | /* Get routing info from the tunnel socket */ |
1116 | skb_dst_drop(skb); | 1132 | skb_dst_drop(skb); |
1117 | skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0))); | 1133 | skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0))); |
@@ -1131,7 +1147,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len | |||
1131 | 1147 | ||
1132 | /* Calculate UDP checksum if configured to do so */ | 1148 | /* Calculate UDP checksum if configured to do so */ |
1133 | #if IS_ENABLED(CONFIG_IPV6) | 1149 | #if IS_ENABLED(CONFIG_IPV6) |
1134 | if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) | 1150 | if (l2tp_sk_is_v6(sk)) |
1135 | udp6_set_csum(udp_get_no_check6_tx(sk), | 1151 | udp6_set_csum(udp_get_no_check6_tx(sk), |
1136 | skb, &inet6_sk(sk)->saddr, | 1152 | skb, &inet6_sk(sk)->saddr, |
1137 | &sk->sk_v6_daddr, udp_len); | 1153 | &sk->sk_v6_daddr, udp_len); |
@@ -1511,24 +1527,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1511 | if (cfg != NULL) | 1527 | if (cfg != NULL) |
1512 | tunnel->debug = cfg->debug; | 1528 | tunnel->debug = cfg->debug; |
1513 | 1529 | ||
1514 | #if IS_ENABLED(CONFIG_IPV6) | ||
1515 | if (sk->sk_family == PF_INET6) { | ||
1516 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
1517 | |||
1518 | if (ipv6_addr_v4mapped(&np->saddr) && | ||
1519 | ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { | ||
1520 | struct inet_sock *inet = inet_sk(sk); | ||
1521 | |||
1522 | tunnel->v4mapped = true; | ||
1523 | inet->inet_saddr = np->saddr.s6_addr32[3]; | ||
1524 | inet->inet_rcv_saddr = sk->sk_v6_rcv_saddr.s6_addr32[3]; | ||
1525 | inet->inet_daddr = sk->sk_v6_daddr.s6_addr32[3]; | ||
1526 | } else { | ||
1527 | tunnel->v4mapped = false; | ||
1528 | } | ||
1529 | } | ||
1530 | #endif | ||
1531 | |||
1532 | /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ | 1530 | /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ |
1533 | tunnel->encap = encap; | 1531 | tunnel->encap = encap; |
1534 | if (encap == L2TP_ENCAPTYPE_UDP) { | 1532 | if (encap == L2TP_ENCAPTYPE_UDP) { |
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index a1aa9550f04e..2718d0b284d0 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -188,9 +188,6 @@ struct l2tp_tunnel { | |||
188 | struct sock *sock; /* Parent socket */ | 188 | struct sock *sock; /* Parent socket */ |
189 | int fd; /* Parent fd, if tunnel socket | 189 | int fd; /* Parent fd, if tunnel socket |
190 | * was created by userspace */ | 190 | * was created by userspace */ |
191 | #if IS_ENABLED(CONFIG_IPV6) | ||
192 | bool v4mapped; | ||
193 | #endif | ||
194 | 191 | ||
195 | struct work_struct del_work; | 192 | struct work_struct del_work; |
196 | 193 | ||