l2tp: add support for IPv4-mapped IPv6 addresses
Subsystems (2)
PATCH 1/1 l2tp: add support for IPv4-mapped IPv6 addresses
IPv4 mapped addresses cause kernel panic.
The patch juste check whether the IPv6 address is an IPv4 mapped address. If so, use IPv4 API instead of IPv6.
Signed-off-by François CACHEREUL <[email protected]>
--- net/l2tp/l2tp_core.c | 28 ++++++++++++++++++++++++---- net/l2tp/l2tp_core.h | 3 +++ 2 files changed, 27 insertions(+), 4 deletions(-)
net/l2tp/l2tp_core.c +24 -4
@@ -496,6 +496,7 @@ out:static inline int l2tp_verify_udp_checksum (struct sock *sk,struct sk_buff *skb) { +struct l2tp_tunnel *tunnel = (struct l2tp_tunnel *)sk->sk_user_data;struct udphdr *uh =udp_hdr (skb);u16 ulen =ntohs (uh->len);__wsum psum;
@@ -504,7 +505,7 @@ static inline int l2tp_verify_udp_checksum(struct sock *sk,return 0 ;#if IS_ENABLED (CONFIG_IPV6 ) -if (sk->sk_family ==PF_INET6 ) { +if (sk->sk_family ==PF_INET6 && !tunnel->v4mapped) {if (!uh->check) {LIMIT_NETDEBUG (KERN_INFO "L2TP: IPv6: checksum is 0\n" );return 1 ;
@@ -1128,7 +1129,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,/* Queue the packet to IP for output */ skb->local_df =1 ;#if IS_ENABLED (CONFIG_IPV6 ) -if (skb->sk->sk_family ==PF_INET6 ) +if (skb->sk->sk_family ==PF_INET6 && !tunnel->v4mapped) error =inet6_csk_xmit (skb,NULL ); else#endif
@@ -1255,7 +1256,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len/* Calculate UDP checksum if configured to do so */ #if IS_ENABLED (CONFIG_IPV6 ) -if (sk->sk_family ==PF_INET6 ) +if (sk->sk_family ==PF_INET6 && !tunnel->v4mapped)l2tp_xmit_ipv6_csum (sk, skb, udp_len); else#endif
@@ -1620,6 +1621,10 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32int err;struct socket *sock =NULL ;struct sock *sk =NULL ; +#if IS_ENABLED (CONFIG_IPV6 ) +struct inet_sock *inet =NULL ; +struct ipv6_pinfo *np =NULL ; +#endif struct l2tp_net *pn;enum l2tp_encap_type encap =L2TP_ENCAPTYPE_UDP ;
@@ -1704,6 +1709,21 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32if (cfg !=NULL ) tunnel->debug = cfg->debug; +#if IS_ENABLED (CONFIG_IPV6 ) + np =inet6_sk (sk); +if (sk->sk_family ==PF_INET6 && +ipv6_addr_v4mapped (&np->saddr) && +ipv6_addr_v4mapped (&np->daddr)) { + tunnel->v4mapped = true; + inet =inet_sk (sk); + inet->inet_saddr = np->saddr.s6_addr32[3 ]; + inet->inet_rcv_saddr = np->rcv_saddr.s6_addr32[3 ]; + inet->inet_daddr = np->daddr.s6_addr32[3 ]; + }else { + tunnel->v4mapped = false; + } +#endif +/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ tunnel->encap = encap;if (encap ==L2TP_ENCAPTYPE_UDP ) {
@@ -1712,7 +1732,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32udp_sk (sk)->encap_rcv = l2tp_udp_encap_recv;udp_sk (sk)->encap_destroy = l2tp_udp_encap_destroy;#if IS_ENABLED (CONFIG_IPV6 ) -if (sk->sk_family ==PF_INET6 ) +if (sk->sk_family ==PF_INET6 && !tunnel->v4mapped)udpv6_encap_enable (); else#endif
net/l2tp/l2tp_core.h +3 -0
@@ -194,6 +194,9 @@ struct l2tp_tunnel {struct sock *sock;/* Parent socket */ int fd;/* Parent fd, if tunnel socket * was created by userspace */ +#if IS_ENABLED (CONFIG_IPV6 ) +bool v4mapped; +#endif struct work_struct del_work;
Signature · 1 line
1.7.10.4
David Miller
maintainerFrom: François Cachereul <[email protected]>
Date: Fri, 27 Sep 2013 13:17:33 +0200
Quoted 8 lines
net/l2tp/l2tp_core.c +4
-0@@ -1620,6 +1621,10 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32int err;struct socket *sock =NULL ;struct sock *sk =NULL ; +#if IS_ENABLED (CONFIG_IPV6 ) +struct inet_sock *inet =NULL ; +struct ipv6_pinfo *np =NULL ; +#endif
...
Quoted 4 lines
net/l2tp/l2tp_core.c +4
-0+#if IS_ENABLED (CONFIG_IPV6 ) + np =inet6_sk (sk); + if (sk->sk_family == PF_INET6 && + ipv6_addr_v4mapped(&np->saddr) &&
net/l2tp/l2tp_core.c int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 · line 1725
Quoted 10 lines
net/l2tp/l2tp_core.c +10
-0+ ipv6_addr_v4mapped(&np->daddr)) { + tunnel->v4mapped = true; + inet = inet_sk(sk); + inet->inet_saddr = np->saddr.s6_addr32[3]; + inet->inet_rcv_saddr = np->rcv_saddr.s6_addr32[3]; + inet->inet_daddr = np->daddr.s6_addr32[3]; + } else { + tunnel->v4mapped = false; + } +#endif
You only need one ifdef here, get rid of the top level variable declarations and then just go:
#if IS_ENABLED(CONFIG_IPV6)
if (sk->sk_family == PF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
if (ipv6_addr_v4mapped(&np->saddr) &&
ipv6_addr_v4mapped(&np->daddr)) {
struct inet_sock *inet = inet_sk(sk);
tunnel->v4mapped = true;
inet->inet_saddr = np->saddr.s6_addr32[3];
inet->inet_rcv_saddr = np->rcv_saddr.s6_addr32[3];
inet->inet_daddr = np->daddr.s6_addr32[3];
} else {
tunnel->v4mapped = false;
}
}#endif