| From foo@baz Sun Jun 17 12:07:34 CEST 2018 |
| From: David Howells <dhowells@redhat.com> |
| Date: Thu, 10 May 2018 23:26:00 +0100 |
| Subject: rxrpc: Fix error reception on AF_INET6 sockets |
| |
| From: David Howells <dhowells@redhat.com> |
| |
| [ Upstream commit f2aeed3a591ff29a82495eeaa92ac4780bad7487 ] |
| |
| AF_RXRPC tries to turn on IP_RECVERR and IP_MTU_DISCOVER on the UDP socket |
| it just opened for communications with the outside world, regardless of the |
| type of socket. Unfortunately, this doesn't work with an AF_INET6 socket. |
| |
| Fix this by turning on IPV6_RECVERR and IPV6_MTU_DISCOVER instead if the |
| socket is of the AF_INET6 family. |
| |
| Without this, kAFS server and address rotation doesn't work correctly |
| because the algorithm doesn't detect received network errors. |
| |
| Fixes: 75b54cb57ca3 ("rxrpc: Add IPv6 support") |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/rxrpc/local_object.c | 57 ++++++++++++++++++++++++++++++++++------------- |
| 1 file changed, 42 insertions(+), 15 deletions(-) |
| |
| --- a/net/rxrpc/local_object.c |
| +++ b/net/rxrpc/local_object.c |
| @@ -133,22 +133,49 @@ static int rxrpc_open_socket(struct rxrp |
| } |
| } |
| |
| - /* we want to receive ICMP errors */ |
| - opt = 1; |
| - ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR, |
| - (char *) &opt, sizeof(opt)); |
| - if (ret < 0) { |
| - _debug("setsockopt failed"); |
| - goto error; |
| - } |
| + switch (local->srx.transport.family) { |
| + case AF_INET: |
| + /* we want to receive ICMP errors */ |
| + opt = 1; |
| + ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR, |
| + (char *) &opt, sizeof(opt)); |
| + if (ret < 0) { |
| + _debug("setsockopt failed"); |
| + goto error; |
| + } |
| + |
| + /* we want to set the don't fragment bit */ |
| + opt = IP_PMTUDISC_DO; |
| + ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER, |
| + (char *) &opt, sizeof(opt)); |
| + if (ret < 0) { |
| + _debug("setsockopt failed"); |
| + goto error; |
| + } |
| + break; |
| + |
| + case AF_INET6: |
| + /* we want to receive ICMP errors */ |
| + opt = 1; |
| + ret = kernel_setsockopt(local->socket, SOL_IPV6, IPV6_RECVERR, |
| + (char *) &opt, sizeof(opt)); |
| + if (ret < 0) { |
| + _debug("setsockopt failed"); |
| + goto error; |
| + } |
| + |
| + /* we want to set the don't fragment bit */ |
| + 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; |
| |
| - /* we want to set the don't fragment bit */ |
| - opt = IP_PMTUDISC_DO; |
| - ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER, |
| - (char *) &opt, sizeof(opt)); |
| - if (ret < 0) { |
| - _debug("setsockopt failed"); |
| - goto error; |
| + default: |
| + BUG(); |
| } |
| |
| /* set the socket up */ |