]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
rxrpc: Fix transport sockopts to get IPv4 errors on an IPv6 socket
authorDavid Howells <dhowells@redhat.com>
Thu, 27 Sep 2018 14:13:09 +0000 (15:13 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jun 2020 06:18:11 +0000 (08:18 +0200)
commit 37a675e768d7606fe8a53e0c459c9b53e121ac20 upstream.

It seems that enabling IPV6_RECVERR on an IPv6 socket doesn't also turn on
IP_RECVERR, so neither local errors nor ICMP-transported remote errors from
IPv4 peer addresses are returned to the AF_RXRPC protocol.

Make the sockopt setting code in rxrpc_open_socket() fall through from the
AF_INET6 case to the AF_INET case to turn on all the AF_INET options too in
the AF_INET6 case.

Fixes: f2aeed3a591f ("rxrpc: Fix error reception on AF_INET6 sockets")
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/rxrpc/local_object.c

index 2af42c7d5b82a55f106232d8f04896f256574c7a..383292adcac6dc4a2bccb12ce3281ca2fe5343b4 100644 (file)
@@ -134,10 +134,10 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
        }
 
        switch (local->srx.transport.family) {
-       case AF_INET:
-               /* we want to receive ICMP errors */
+       case AF_INET6:
+               /* we want to receive ICMPv6 errors */
                opt = 1;
-               ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR,
+               ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_RECVERR,
                                        (char *) &opt, sizeof(opt));
                if (ret < 0) {
                        _debug("setsockopt failed");
@@ -145,19 +145,22 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
                }
 
                /* we want to set the don't fragment bit */
-               opt = IP_PMTUDISC_DO;
-               ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER,
+               opt = IPV6_PMTUDISC_DO;
+               ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_MTU_DISCOVER,
                                        (char *) &opt, sizeof(opt));
                if (ret < 0) {
                        _debug("setsockopt failed");
                        goto error;
                }
-               break;
 
-       case AF_INET6:
+               /* Fall through and set IPv4 options too otherwise we don't get
+                * errors from IPv4 packets sent through the IPv6 socket.
+                */
+
+       case AF_INET:
                /* we want to receive ICMP errors */
                opt = 1;
-               ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_RECVERR,
+               ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR,
                                        (char *) &opt, sizeof(opt));
                if (ret < 0) {
                        _debug("setsockopt failed");
@@ -165,8 +168,8 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
                }
 
                /* we want to set the don't fragment bit */
-               opt = IPV6_PMTUDISC_DO;
-               ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_MTU_DISCOVER,
+               opt = IP_PMTUDISC_DO;
+               ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER,
                                        (char *) &opt, sizeof(opt));
                if (ret < 0) {
                        _debug("setsockopt failed");