// SPDX-License-Identifier: GPL-2.0-or-later
/*
* RAW sockets for IPv6
* Linux INET6 implementation
*
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
* Adapted from linux/net/ipv4/raw.c
*
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance)
* Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/slab.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/icmpv6.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
#include <linux/skbuff.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
#include <asm/ioctls.h>
#include <net/net_namespace.h>
#include <net/ip.h>
#include <net/sock.h>
#include <net/snmp.h>
#include <net/ipv6.h>
#include <net/ndisc.h>
#include <net/protocol.h>
#include <net/ip6_route.h>
#include <net/ip6_checksum.h>
#include <net/addrconf.h>
#include <net/transp_v6.h>
#include <net/udp.h>
#include <net/inet_common.h>
#include <net/tcp_states.h>
#if IS_ENABLED(CONFIG_IPV6_MIP6)
#include <net/mip6.h>
#endif
#include <linux/mroute6.h>
#include <net/raw.h>
#include <net/rawv6.h>
#include <net/xfrm.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/export.h>
#define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */
struct raw_hashinfo raw_v6_hashinfo;
EXPORT_SYMBOL_GPL(raw_v6_hashinfo);
bool raw_v6_match(struct net *net, const struct sock *sk, unsigned short num,
const struct in6_addr *loc_addr,
const struct in6_addr *rmt_addr, int dif, int sdif)
{
if (inet_sk(sk)->inet_num != num ||
!net_eq(sock_net(sk), net) ||
(!ipv6_addr_any(&sk->sk_v6_daddr) &&
!ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) ||
!raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if,
dif, sdif))
return false;
if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) ||
ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr) ||
(ipv6_addr_is_multicast(loc_addr) &&
inet6_mc_check(sk, loc_addr, rmt_addr)))
return true;
return false;
}
EXPORT_SYMBOL_GPL(raw_v6_match);
/*
* 0 - deliver
* 1 - block
*/
static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb)
{
struct icmp6hdr _hdr;
const struct icmp6hdr *hdr;
/* We require only the four bytes of the ICMPv6 header, not any
* additional bytes of message body in "struct icmp6hdr".
*/
hdr = skb_header_pointer(skb, skb_transport_offset(skb),
ICMPV6_HDRLEN, &_hdr);
if (hdr) <