7b674e390e
Fix IPv6 support in AF_RXRPC in the following ways: (1) When extracting the address from a received IPv4 packet, if the local transport socket is open for IPv6 then fill out the sockaddr_rxrpc struct for an IPv4-mapped-to-IPv6 AF_INET6 transport address instead of an AF_INET one. (2) When sending CHALLENGE or RESPONSE packets, the transport length needs to be set from the sockaddr_rxrpc::transport_len field rather than sizeof() on the IPv4 transport address. (3) When processing an IPv4 ICMP packet received by an IPv6 socket, set up the address correctly before searching for the affected peer. Signed-off-by: David Howells <dhowells@redhat.com>
60 lines
1.8 KiB
C
60 lines
1.8 KiB
C
/* Utility routines
|
|
*
|
|
* Copyright (C) 2015 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public Licence
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the Licence, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/ip.h>
|
|
#include <linux/ipv6.h>
|
|
#include <linux/udp.h>
|
|
#include "ar-internal.h"
|
|
|
|
/*
|
|
* Fill out a peer address from a socket buffer containing a packet.
|
|
*/
|
|
int rxrpc_extract_addr_from_skb(struct rxrpc_local *local,
|
|
struct sockaddr_rxrpc *srx,
|
|
struct sk_buff *skb)
|
|
{
|
|
memset(srx, 0, sizeof(*srx));
|
|
|
|
switch (ntohs(skb->protocol)) {
|
|
case ETH_P_IP:
|
|
if (local->srx.transport.family == AF_INET6) {
|
|
srx->transport_type = SOCK_DGRAM;
|
|
srx->transport_len = sizeof(srx->transport.sin6);
|
|
srx->transport.sin6.sin6_family = AF_INET6;
|
|
srx->transport.sin6.sin6_port = udp_hdr(skb)->source;
|
|
srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
|
|
srx->transport.sin6.sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr;
|
|
} else {
|
|
srx->transport_type = SOCK_DGRAM;
|
|
srx->transport_len = sizeof(srx->transport.sin);
|
|
srx->transport.sin.sin_family = AF_INET;
|
|
srx->transport.sin.sin_port = udp_hdr(skb)->source;
|
|
srx->transport.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
|
|
}
|
|
return 0;
|
|
|
|
#ifdef CONFIG_AF_RXRPC_IPV6
|
|
case ETH_P_IPV6:
|
|
srx->transport_type = SOCK_DGRAM;
|
|
srx->transport_len = sizeof(srx->transport.sin6);
|
|
srx->transport.sin6.sin6_family = AF_INET6;
|
|
srx->transport.sin6.sin6_port = udp_hdr(skb)->source;
|
|
srx->transport.sin6.sin6_addr = ipv6_hdr(skb)->saddr;
|
|
return 0;
|
|
#endif
|
|
|
|
default:
|
|
pr_warn_ratelimited("AF_RXRPC: Unknown eth protocol %u\n",
|
|
ntohs(skb->protocol));
|
|
return -EAFNOSUPPORT;
|
|
}
|
|
}
|