Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75b54cb5 authored by David Howells's avatar David Howells
Browse files

rxrpc: Add IPv6 support



Add IPv6 support to AF_RXRPC.  With this, AF_RXRPC sockets can be created:

	service = socket(AF_RXRPC, SOCK_DGRAM, PF_INET6);

instead of:

	service = socket(AF_RXRPC, SOCK_DGRAM, PF_INET);

The AFS filesystem doesn't support IPv6 at the moment, though, since that
requires upgrades to some of the RPC calls.

Note that a good portion of this patch is replacing "%pI4:%u" in print
statements with "%pISpc" which is able to handle both protocols and print
the port.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 1c2bc7b9
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -106,19 +106,23 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
	case AF_INET:
		if (srx->transport_len < sizeof(struct sockaddr_in))
			return -EINVAL;
		_debug("INET: %x @ %pI4",
		       ntohs(srx->transport.sin.sin_port),
		       &srx->transport.sin.sin_addr);
		tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
		break;

	case AF_INET6:
		if (srx->transport_len < sizeof(struct sockaddr_in6))
			return -EINVAL;
		tail = offsetof(struct sockaddr_rxrpc, transport) +
			sizeof(struct sockaddr_in6);
		break;

	default:
		return -EAFNOSUPPORT;
	}

	if (tail < len)
		memset((void *)srx + tail, 0, len - tail);
	_debug("INET: %pISp", &srx->transport);
	return 0;
}

@@ -409,6 +413,9 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
		case AF_INET:
			rx->srx.transport_len = sizeof(struct sockaddr_in);
			break;
		case AF_INET6:
			rx->srx.transport_len = sizeof(struct sockaddr_in6);
			break;
		default:
			ret = -EAFNOSUPPORT;
			goto error_unlock;
@@ -563,7 +570,7 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
		return -EAFNOSUPPORT;

	/* we support transport protocol UDP/UDP6 only */
	if (protocol != PF_INET)
	if (protocol != PF_INET && protocol != PF_INET6)
		return -EPROTONOSUPPORT;

	if (sock->type != SOCK_DGRAM)
+8 −0
Original line number Diff line number Diff line
@@ -134,6 +134,14 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local,
			    srx.transport.sin.sin_addr.s_addr)
				goto not_found;
			break;
		case AF_INET6:
			if (peer->srx.transport.sin6.sin6_port !=
			    srx.transport.sin6.sin6_port ||
			    memcmp(&peer->srx.transport.sin6.sin6_addr,
				   &srx.transport.sin6.sin6_addr,
				   sizeof(struct in6_addr)) != 0)
				goto not_found;
			break;
		default:
			BUG();
		}
+15 −20
Original line number Diff line number Diff line
@@ -58,6 +58,15 @@ static long rxrpc_local_cmp_key(const struct rxrpc_local *local,
			memcmp(&local->srx.transport.sin.sin_addr,
			       &srx->transport.sin.sin_addr,
			       sizeof(struct in_addr));
	case AF_INET6:
		/* If the choice of UDP6 port is left up to the transport, then
		 * the endpoint record doesn't match.
		 */
		return ((u16 __force)local->srx.transport.sin6.sin6_port -
			(u16 __force)srx->transport.sin6.sin6_port) ?:
			memcmp(&local->srx.transport.sin6.sin6_addr,
			       &srx->transport.sin6.sin6_addr,
			       sizeof(struct in6_addr));
	default:
		BUG();
	}
@@ -100,7 +109,8 @@ static int rxrpc_open_socket(struct rxrpc_local *local)
	struct sock *sock;
	int ret, opt;

	_enter("%p{%d}", local, local->srx.transport_type);
	_enter("%p{%d,%d}",
	       local, local->srx.transport_type, local->srx.transport.family);

	/* create a socket to represent the local endpoint */
	ret = sock_create_kern(&init_net, local->srx.transport.family,
@@ -169,18 +179,8 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
	long diff;
	int ret;

	if (srx->transport.family == AF_INET) {
		_enter("{%d,%u,%pI4+%hu}",
		       srx->transport_type,
		       srx->transport.family,
		       &srx->transport.sin.sin_addr,
		       ntohs(srx->transport.sin.sin_port));
	} else {
		_enter("{%d,%u}",
		       srx->transport_type,
		       srx->transport.family);
		return ERR_PTR(-EAFNOSUPPORT);
	}
	_enter("{%d,%d,%pISp}",
	       srx->transport_type, srx->transport.family, &srx->transport);

	mutex_lock(&rxrpc_local_mutex);

@@ -233,13 +233,8 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
found:
	mutex_unlock(&rxrpc_local_mutex);

	_net("LOCAL %s %d {%d,%u,%pI4+%hu}",
	     age,
	     local->debug_id,
	     local->srx.transport_type,
	     local->srx.transport.family,
	     &local->srx.transport.sin.sin_addr,
	     ntohs(local->srx.transport.sin.sin_port));
	_net("LOCAL %s %d {%pISp}",
	     age, local->debug_id, &local->srx.transport);

	_leave(" = %p", local);
	return local;
+16 −0
Original line number Diff line number Diff line
@@ -258,6 +258,22 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
					  (char *)&opt, sizeof(opt));
		}
		break;

	case AF_INET6:
		opt = IPV6_PMTUDISC_DONT;
		ret = kernel_setsockopt(conn->params.local->socket,
					SOL_IPV6, IPV6_MTU_DISCOVER,
					(char *)&opt, sizeof(opt));
		if (ret == 0) {
			ret = kernel_sendmsg(conn->params.local->socket, &msg,
					     iov, 1, iov[0].iov_len);

			opt = IPV6_PMTUDISC_DO;
			kernel_setsockopt(conn->params.local->socket,
					  SOL_IPV6, IPV6_MTU_DISCOVER,
					  (char *)&opt, sizeof(opt));
		}
		break;
	}

	up_write(&conn->params.local->defrag_sem);
+24 −0
Original line number Diff line number Diff line
@@ -66,6 +66,30 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local,
		}
		break;

	case AF_INET6:
		srx.transport.sin6.sin6_port = serr->port;
		srx.transport_len = sizeof(struct sockaddr_in6);
		switch (serr->ee.ee_origin) {
		case SO_EE_ORIGIN_ICMP6:
			_net("Rx ICMP6");
			memcpy(&srx.transport.sin6.sin6_addr,
			       skb_network_header(skb) + serr->addr_offset,
			       sizeof(struct in6_addr));
			break;
		case SO_EE_ORIGIN_ICMP:
			_net("Rx ICMP on v6 sock");
			memcpy(&srx.transport.sin6.sin6_addr.s6_addr + 12,
			       skb_network_header(skb) + serr->addr_offset,
			       sizeof(struct in_addr));
			break;
		default:
			memcpy(&srx.transport.sin6.sin6_addr,
			       &ipv6_hdr(skb)->saddr,
			       sizeof(struct in6_addr));
			break;
		}
		break;

	default:
		BUG();
	}
Loading