Skip to content

Commit

Permalink
Merge tag 'rxrpc-rewrite-20160913-2' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…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: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Sep 16, 2016
2 parents 39caa8b + 75b54cb commit 364eac0
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 119 deletions.
27 changes: 23 additions & 4 deletions net/rxrpc/af_rxrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

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

switch (rx->sk.sk_state) {
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);
if (IS_ERR(local)) {
ret = PTR_ERR(local);
Expand Down Expand Up @@ -551,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)
Expand Down
8 changes: 8 additions & 0 deletions net/rxrpc/conn_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
13 changes: 5 additions & 8 deletions net/rxrpc/local_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <generated/utsrelease.h>
Expand All @@ -33,20 +31,19 @@ static void rxrpc_send_version_request(struct rxrpc_local *local,
{
struct rxrpc_wire_header whdr;
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
struct sockaddr_in sin;
struct sockaddr_rxrpc srx;
struct msghdr msg;
struct kvec iov[2];
size_t len;
int ret;

_enter("");

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

msg.msg_name = &sin;
msg.msg_namelen = sizeof(sin);
msg.msg_name = &srx.transport;
msg.msg_namelen = srx.transport_len;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
Expand Down
39 changes: 17 additions & 22 deletions net/rxrpc/local_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -100,11 +109,12 @@ 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, PF_INET, local->srx.transport_type,
IPPROTO_UDP, &local->socket);
ret = sock_create_kern(&init_net, local->srx.transport.family,
local->srx.transport_type, 0, &local->socket);
if (ret < 0) {
_leave(" = %d [socket]", ret);
return ret;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
48 changes: 22 additions & 26 deletions net/rxrpc/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
#include <linux/gfp.h>
#include <linux/skbuff.h>
#include <linux/export.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include "ar-internal.h"
Expand Down Expand Up @@ -260,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);
Expand All @@ -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)
{
union {
struct sockaddr sa;
struct sockaddr_in sin;
} sa;
struct sockaddr_rxrpc srx;
struct rxrpc_skb_priv *sp;
struct rxrpc_wire_header whdr;
struct sk_buff *skb;
Expand All @@ -292,32 +303,21 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
iov[1].iov_len = sizeof(code);
size = sizeof(whdr) + sizeof(code);

msg.msg_name = &sa;
msg.msg_name = &srx.transport;
msg.msg_control = NULL;
msg.msg_controllen = 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));
whdr.type = RXRPC_PACKET_TYPE_ABORT;

while ((skb = skb_dequeue(&local->reject_queue))) {
rxrpc_see_skb(skb);
sp = rxrpc_skb(skb);
switch (sa.sa.sa_family) {
case AF_INET:
sa.sin.sin_port = udp_hdr(skb)->source;
sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;

if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) {
msg.msg_namelen = srx.transport_len;

code = htonl(skb->priority);

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

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

default:
break;
}

rxrpc_free_skb(skb);
Expand Down
24 changes: 24 additions & 0 deletions net/rxrpc/peer_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Loading

0 comments on commit 364eac0

Please sign in to comment.