Re: Ooops with SCTP

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jul 07, 2014 at 01:39:41PM -0600, Jason Gunthorpe wrote:
> On Mon, Jul 07, 2014 at 02:22:36PM -0400, Neil Horman wrote:
> 
> > I'll try get to expanding this patch in the next few days
> 
> Sure, I should be able to test your expansion on the patch I sent, let
> me know.
> 
> Regards,
> Jason
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


Sorry for the delay, busy few days.  I think this fixes up all the required call
sites that check v4mapped.  I've not tested it yet, but it builds.  If you could
please give it a spin and let me know, I'll officially propose it.

Thanks!
Neil


commit 469f5a1527ffcdd08fdcb1c45c80b840f9a7819c
Author: Neil Horman <nhorman@xxxxxxxxxxxxx>
Date:   Wed Jul 9 11:36:33 2014 -0400

    sctp: Fixup v4mapped behavior to comply with Sock API
    
    The SCTP socket extensions API document describes the v4mapping option as
    follows:
    
    8.1.15.  Set/Clear IPv4 Mapped Addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
    
       This socket option is a boolean flag which turns on or off the
       mapping of IPv4 addresses.  If this option is turned on, then IPv4
       addresses will be mapped to V6 representation.  If this option is
       turned off, then no mapping will be done of V4 addresses and a user
       will receive both PF_INET6 and PF_INET type addresses on the socket.
       See [RFC3542] for more details on mapped V6 addresses.
    
    This description isn't really in line with what the code does though.  If we
    have an AF_INET6 socket, that recieves a ipv4 frame and MAPPED_V4_ADDR isn't
    set, it either ignores the frame, or drops the address into an ipv6 sockaddr_in6
    structure in the wrong place (with the wrong sa_family field set).  We need to
    construct proper sockaddr_in structures when handling AF_INET packets on
    AF_INET6 sockets when MAPPED_V4_ADDR is set to 0.
    
    Signed-off-by: Neil Horman <nhorman@xxxxxxxxxxxxx>

diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 1999592..5261ac5 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -434,12 +434,17 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 /* Initialize sk->sk_rcv_saddr from sctp_addr. */
 static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 {
-	if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
-		sk->sk_v6_rcv_saddr.s6_addr32[0] = 0;
-		sk->sk_v6_rcv_saddr.s6_addr32[1] = 0;
-		sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
-		sk->sk_v6_rcv_saddr.s6_addr32[3] =
+	if (addr->sa.sa_family == AF_INET) {
+		if (sctp_sk(sk)->v4mapped) {
+			sk->sk_v6_rcv_saddr.s6_addr32[0] = 0;
+			sk->sk_v6_rcv_saddr.s6_addr32[1] = 0;
+			sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
+			sk->sk_v6_rcv_saddr.s6_addr32[3] =
 			addr->v4.sin_addr.s_addr;
+		} else {
+			inet_sk(sk)->inet_rcv_saddr =
+			addr->v4.sin_addr.s_addr;
+		}
 	} else {
 		sk->sk_v6_rcv_saddr = addr->v6.sin6_addr;
 	}
@@ -448,11 +453,16 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 /* Initialize sk->sk_daddr from sctp_addr. */
 static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
 {
-	if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
-		sk->sk_v6_daddr.s6_addr32[0] = 0;
-		sk->sk_v6_daddr.s6_addr32[1] = 0;
-		sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
-		sk->sk_v6_daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
+	if (addr->sa.sa_family == AF_INET) {
+		if (sctp_sk(sk)->v4mapped) {
+			sk->sk_v6_daddr.s6_addr32[0] = 0;
+			sk->sk_v6_daddr.s6_addr32[1] = 0;
+			sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
+			sk->sk_v6_daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
+		} else {
+			inet_sk(sk)->inet_daddr = addr->v4.sin_addr.s_addr;
+		}
+
 	} else {
 		sk->sk_v6_daddr = addr->v6.sin6_addr;
 	}
@@ -556,11 +566,10 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
 	if (IPV6_ADDR_ANY == type)
 		return 1;
 	if (type == IPV6_ADDR_MAPPED) {
-		if (sp && !sp->v4mapped)
-			return 0;
 		if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
 			return 0;
-		sctp_v6_map_v4(addr);
+		if (sp && sp->v4mapped)
+			sctp_v6_map_v4(addr);
 		return sctp_get_af_specific(AF_INET)->available(addr, sp);
 	}
 	if (!(type & IPV6_ADDR_UNICAST))
@@ -587,11 +596,10 @@ static int sctp_v6_addr_valid(union sctp_addr *addr,
 		/* Note: This routine is used in input, so v4-mapped-v6
 		 * are disallowed here when there is no sctp_sock.
 		 */
-		if (!sp || !sp->v4mapped)
-			return 0;
 		if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
 			return 0;
-		sctp_v6_map_v4(addr);
+		if (sp && sp->v4mapped)
+			sctp_v6_map_v4(addr);
 		return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb);
 	}
 
@@ -723,6 +731,7 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
 				     char *msgname, int *addrlen)
 {
 	struct sockaddr_in6 *sin6, *sin6from;
+	struct sockaddr_in *sin;
 
 	if (msgname) {
 		union sctp_addr *addr;
@@ -731,6 +740,7 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
 		asoc = event->asoc;
 		sctp_inet6_msgname(msgname, addrlen);
 		sin6 = (struct sockaddr_in6 *)msgname;
+		sin = (struct sockaddr_in *)msgname;
 		sin6->sin6_port = htons(asoc->peer.port);
 		addr = &asoc->peer.primary_addr;
 
@@ -739,12 +749,16 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
 		 */
 
 		/* Map ipv4 address into v4-mapped-on-v6 address.  */
-		if (sctp_sk(asoc->base.sk)->v4mapped &&
-		    AF_INET == addr->sa.sa_family) {
-			sctp_v4_map_v6((union sctp_addr *)sin6);
-			sin6->sin6_addr.s6_addr32[3] =
-				addr->v4.sin_addr.s_addr;
-			return;
+		if (addr->sa.sa_family == AF_INET) {
+			if (sctp_sk(asoc->base.sk)->v4mapped) {
+				sctp_v4_map_v6((union sctp_addr *)sin6);
+				sin6->sin6_addr.s6_addr32[3] =
+					addr->v4.sin_addr.s_addr;
+				return;
+			} else {
+				sin->sin_addr.s_addr = addr->v4.sin_addr.s_addr;
+				sin->sin_family = AF_INET;
+			}
 		}
 
 		sin6from = &asoc->peer.primary_addr.v6;
@@ -760,22 +774,31 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
 {
 	struct sctphdr *sh;
 	struct sockaddr_in6 *sin6;
+	struct sockaddr_in *sin;
 
 	if (msgname) {
 		sctp_inet6_msgname(msgname, addr_len);
 		sin6 = (struct sockaddr_in6 *)msgname;
+		sin = (struct sockaddr_in *)msgname;
+
 		sh = sctp_hdr(skb);
-		sin6->sin6_port = sh->source;
 
 		/* Map ipv4 address into v4-mapped-on-v6 address. */
-		if (sctp_sk(skb->sk)->v4mapped &&
-		    ip_hdr(skb)->version == 4) {
-			sctp_v4_map_v6((union sctp_addr *)sin6);
-			sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr;
+		if (ip_hdr(skb)->version == 4) {
+			if (sctp_sk(skb->sk)->v4mapped) {
+				sin6->sin6_port = sh->source;
+				sctp_v4_map_v6((union sctp_addr *)sin6);
+				sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr;
+			} else {
+				sin->sin_addr.s_addr =  ip_hdr(skb)->saddr;
+				sin->sin_family = AF_INET;
+				sin->sin_port = sh->source;
+			}
 			return;
 		}
 
 		/* Otherwise, just copy the v6 address. */
+		sin6->sin6_port = sh->source;
 		sin6->sin6_addr = ipv6_hdr(skb)->saddr;
 		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
 			struct sctp_ulpevent *ev = sctp_skb2event(skb);
--
To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Networking Development]     [Linux OMAP]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux