From 299ee123e19889d511092347f5fc14db0f10e3a6 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 30 Jul 2014 12:40:53 -0600 Subject: sctp: Fixup v4mapped behaviour 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. Introduce addr_to_user (renamed addr_v4map), which should be called before any sockaddr is passed back to user space. The new function places the sockaddr into the correct format depending on the SCTP_I_WANT_MAPPED_V4_ADDR option. Audit all places that touched v4mapped and either sanely construct a v4 or v6 address then call addr_to_user, or drop the unnecessary v4mapped check entirely. Audit all places that call addr_to_user and verify they are on a sycall return path. Add a custom getname that formats the address properly. Several bugs are addressed: - SCTP_I_WANT_MAPPED_V4_ADDR=0 often returned garbage for addresses to user space - The addr_len returned from recvmsg was not correct when returning AF_INET on a v6 socket - flowlabel and scope_id were not zerod when promoting a v4 to v6 - Some syscalls like bind and connect behaved differently depending on v4mapped Tested bind, getpeername, getsockname, connect, and recvmsg for proper behaviour in v4mapped = 1 and 0 cases. Signed-off-by: Neil Horman Tested-by: Jason Gunthorpe Signed-off-by: Jason Gunthorpe Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 2 ++ include/net/sctp/structs.h | 8 +++----- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/net/sctp') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 90c1cccd164d..f6e7397e799d 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -554,6 +554,8 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr) static inline void sctp_v4_map_v6(union sctp_addr *addr) { addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_flowinfo = 0; + addr->v6.sin6_scope_id = 0; addr->v6.sin6_port = addr->v4.sin_port; addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; addr->v6.sin6_addr.s6_addr32[0] = 0; diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7741d1b66967..4ff3f67be62c 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -465,10 +465,6 @@ struct sctp_af { int saddr); void (*from_sk) (union sctp_addr *, struct sock *sk); - void (*to_sk_saddr) (union sctp_addr *, - struct sock *sk); - void (*to_sk_daddr) (union sctp_addr *, - struct sock *sk); void (*from_addr_param) (union sctp_addr *, union sctp_addr_param *, __be16 port, int iif); @@ -509,7 +505,9 @@ struct sctp_pf { int (*supported_addrs)(const struct sctp_sock *, __be16 *); struct sock *(*create_accept_sk) (struct sock *sk, struct sctp_association *asoc); - void (*addr_v4map) (struct sctp_sock *, union sctp_addr *); + int (*addr_to_user)(struct sctp_sock *sk, union sctp_addr *addr); + void (*to_sk_saddr)(union sctp_addr *, struct sock *sk); + void (*to_sk_daddr)(union sctp_addr *, struct sock *sk); struct sctp_af *af; }; -- cgit v1.2.3-58-ga151