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

Commit 364eac0c authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'rxrpc-rewrite-20160913-2' of...

Merge tag 'rxrpc-rewrite-20160913-2' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs



David Howells says:

====================
rxrpc: Support IPv6

Here is a set of patches that add IPv6 support.  They need to be applied on
top of the just-posted miscellaneous fix patches.  They are:

 (1) Make autobinding of an unconnected socket work when sendmsg() is
     called to initiate a client call.

 (2) Don't specify the protocol when creating the client socket, but rather
     take the default instead.

 (3) Use rxrpc_extract_addr_from_skb() in a couple of places that were
     doing the same thing manually.  This allows the IPv6 address
     extraction to be done in fewer places.

 (4) Add IPv6 support.  With this, calls can be made to IPv6 servers from
     userspace AF_RXRPC programs; AFS, however, can't use IPv6 yet as the
     RPC calls need to be upgradeable.
====================

Reviewed-by: default avatarSteve Wise <swise@opengridcomputing.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 39caa8bf 75b54cb5
Loading
Loading
Loading
Loading
+23 −4
Original line number Original line Diff line number Diff line
@@ -106,19 +106,23 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
	case AF_INET:
	case AF_INET:
		if (srx->transport_len < sizeof(struct sockaddr_in))
		if (srx->transport_len < sizeof(struct sockaddr_in))
			return -EINVAL;
			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);
		tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
		break;
		break;


	case AF_INET6:
	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:
	default:
		return -EAFNOSUPPORT;
		return -EAFNOSUPPORT;
	}
	}


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


@@ -401,6 +405,21 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)


	switch (rx->sk.sk_state) {
	switch (rx->sk.sk_state) {
	case RXRPC_UNBOUND:
	case RXRPC_UNBOUND:
		rx->srx.srx_family = AF_RXRPC;
		rx->srx.srx_service = 0;
		rx->srx.transport_type = SOCK_DGRAM;
		rx->srx.transport.family = rx->family;
		switch (rx->family) {
		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;
		}
		local = rxrpc_lookup_local(&rx->srx);
		local = rxrpc_lookup_local(&rx->srx);
		if (IS_ERR(local)) {
		if (IS_ERR(local)) {
			ret = PTR_ERR(local);
			ret = PTR_ERR(local);
@@ -551,7 +570,7 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
		return -EAFNOSUPPORT;
		return -EAFNOSUPPORT;


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


	if (sock->type != SOCK_DGRAM)
	if (sock->type != SOCK_DGRAM)
+8 −0
Original line number Original line 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)
			    srx.transport.sin.sin_addr.s_addr)
				goto not_found;
				goto not_found;
			break;
			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:
		default:
			BUG();
			BUG();
		}
		}
+5 −8
Original line number Original line Diff line number Diff line
@@ -15,8 +15,6 @@
#include <linux/net.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <net/sock.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <net/af_rxrpc.h>
#include <generated/utsrelease.h>
#include <generated/utsrelease.h>
@@ -33,7 +31,7 @@ static void rxrpc_send_version_request(struct rxrpc_local *local,
{
{
	struct rxrpc_wire_header whdr;
	struct rxrpc_wire_header whdr;
	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
	struct sockaddr_in sin;
	struct sockaddr_rxrpc srx;
	struct msghdr msg;
	struct msghdr msg;
	struct kvec iov[2];
	struct kvec iov[2];
	size_t len;
	size_t len;
@@ -41,12 +39,11 @@ static void rxrpc_send_version_request(struct rxrpc_local *local,


	_enter("");
	_enter("");


	sin.sin_family = AF_INET;
	if (rxrpc_extract_addr_from_skb(&srx, skb) < 0)
	sin.sin_port = udp_hdr(skb)->source;
		return;
	sin.sin_addr.s_addr = ip_hdr(skb)->saddr;


	msg.msg_name	= &sin;
	msg.msg_name	= &srx.transport;
	msg.msg_namelen	= sizeof(sin);
	msg.msg_namelen	= srx.transport_len;
	msg.msg_control	= NULL;
	msg.msg_control	= NULL;
	msg.msg_controllen = 0;
	msg.msg_controllen = 0;
	msg.msg_flags	= 0;
	msg.msg_flags	= 0;
+17 −22
Original line number Original line 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,
			memcmp(&local->srx.transport.sin.sin_addr,
			       &srx->transport.sin.sin_addr,
			       &srx->transport.sin.sin_addr,
			       sizeof(struct in_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:
	default:
		BUG();
		BUG();
	}
	}
@@ -100,11 +109,12 @@ static int rxrpc_open_socket(struct rxrpc_local *local)
	struct sock *sock;
	struct sock *sock;
	int ret, opt;
	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 */
	/* create a socket to represent the local endpoint */
	ret = sock_create_kern(&init_net, PF_INET, local->srx.transport_type,
	ret = sock_create_kern(&init_net, local->srx.transport.family,
			       IPPROTO_UDP, &local->socket);
			       local->srx.transport_type, 0, &local->socket);
	if (ret < 0) {
	if (ret < 0) {
		_leave(" = %d [socket]", ret);
		_leave(" = %d [socket]", ret);
		return ret;
		return ret;
@@ -169,18 +179,8 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
	long diff;
	long diff;
	int ret;
	int ret;


	if (srx->transport.family == AF_INET) {
	_enter("{%d,%d,%pISp}",
		_enter("{%d,%u,%pI4+%hu}",
	       srx->transport_type, srx->transport.family, &srx->transport);
		       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);
	}


	mutex_lock(&rxrpc_local_mutex);
	mutex_lock(&rxrpc_local_mutex);


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


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


	_leave(" = %p", local);
	_leave(" = %p", local);
	return local;
	return local;
+22 −26
Original line number Original line Diff line number Diff line
@@ -15,8 +15,6 @@
#include <linux/gfp.h>
#include <linux/gfp.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/export.h>
#include <linux/export.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <net/sock.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <net/af_rxrpc.h>
#include "ar-internal.h"
#include "ar-internal.h"
@@ -260,6 +258,22 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
					  (char *)&opt, sizeof(opt));
					  (char *)&opt, sizeof(opt));
		}
		}
		break;
		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);
	up_write(&conn->params.local->defrag_sem);
@@ -272,10 +286,7 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
 */
 */
void rxrpc_reject_packets(struct rxrpc_local *local)
void rxrpc_reject_packets(struct rxrpc_local *local)
{
{
	union {
	struct sockaddr_rxrpc srx;
		struct sockaddr sa;
		struct sockaddr_in sin;
	} sa;
	struct rxrpc_skb_priv *sp;
	struct rxrpc_skb_priv *sp;
	struct rxrpc_wire_header whdr;
	struct rxrpc_wire_header whdr;
	struct sk_buff *skb;
	struct sk_buff *skb;
@@ -292,32 +303,21 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
	iov[1].iov_len = sizeof(code);
	iov[1].iov_len = sizeof(code);
	size = sizeof(whdr) + sizeof(code);
	size = sizeof(whdr) + sizeof(code);


	msg.msg_name = &sa;
	msg.msg_name = &srx.transport;
	msg.msg_control = NULL;
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;
	msg.msg_flags = 0;


	memset(&sa, 0, sizeof(sa));
	sa.sa.sa_family = local->srx.transport.family;
	switch (sa.sa.sa_family) {
	case AF_INET:
		msg.msg_namelen = sizeof(sa.sin);
		break;
	default:
		msg.msg_namelen = 0;
		break;
	}

	memset(&whdr, 0, sizeof(whdr));
	memset(&whdr, 0, sizeof(whdr));
	whdr.type = RXRPC_PACKET_TYPE_ABORT;
	whdr.type = RXRPC_PACKET_TYPE_ABORT;


	while ((skb = skb_dequeue(&local->reject_queue))) {
	while ((skb = skb_dequeue(&local->reject_queue))) {
		rxrpc_see_skb(skb);
		rxrpc_see_skb(skb);
		sp = rxrpc_skb(skb);
		sp = rxrpc_skb(skb);
		switch (sa.sa.sa_family) {

		case AF_INET:
		if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) {
			sa.sin.sin_port = udp_hdr(skb)->source;
			msg.msg_namelen = srx.transport_len;
			sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;

			code = htonl(skb->priority);
			code = htonl(skb->priority);


			whdr.epoch	= htonl(sp->hdr.epoch);
			whdr.epoch	= htonl(sp->hdr.epoch);
@@ -329,10 +329,6 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
			whdr.flags	&= RXRPC_CLIENT_INITIATED;
			whdr.flags	&= RXRPC_CLIENT_INITIATED;


			kernel_sendmsg(local->socket, &msg, iov, 2, size);
			kernel_sendmsg(local->socket, &msg, iov, 2, size);
			break;

		default:
			break;
		}
		}


		rxrpc_free_skb(skb);
		rxrpc_free_skb(skb);
Loading