aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/datagram.c21
-rw-r--r--net/l2tp/l2tp_core.c38
-rw-r--r--net/l2tp/l2tp_core.h3
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)
115static 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
115static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) 122static 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