| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* OpenVPN data channel offload | |
| * | |
| * Copyright (C) 2012-2025 OpenVPN, Inc. | |
| * | |
| * Author: James Yonan <james@openvpn.net> | |
| * Antonio Quartulli <antonio@openvpn.net> | |
| */ | |
| #ifndef _NET_OVPN_OVPNBIND_H_ | |
| #define _NET_OVPN_OVPNBIND_H_ | |
| #include <net/ip.h> | |
| #include <linux/in.h> | |
| #include <linux/in6.h> | |
| #include <linux/rcupdate.h> | |
| #include <linux/skbuff.h> | |
| #include <linux/spinlock.h> | |
| struct ovpn_peer; | |
| /** | |
| * union ovpn_sockaddr - basic transport layer address | |
| * @in4: IPv4 address | |
| * @in6: IPv6 address | |
| */ | |
| union ovpn_sockaddr { | |
| struct sockaddr_in in4; | |
| struct sockaddr_in6 in6; | |
| }; | |
| /** | |
| * struct ovpn_bind - remote peer binding | |
| * @remote: the remote peer sockaddress | |
| * @local: local endpoint used to talk to the peer | |
| * @local.ipv4: local IPv4 used to talk to the peer | |
| * @local.ipv6: local IPv6 used to talk to the peer | |
| * @rcu: used to schedule RCU cleanup job | |
| */ | |
| struct ovpn_bind { | |
| union ovpn_sockaddr remote; /* remote sockaddr */ | |
| union { | |
| struct in_addr ipv4; | |
| struct in6_addr ipv6; | |
| } local; | |
| struct rcu_head rcu; | |
| }; | |
| /** | |
| * ovpn_bind_skb_src_match - match packet source with binding | |
| * @bind: the binding to match | |
| * @skb: the packet to match | |
| * | |
| * Return: true if the packet source matches the remote peer sockaddr | |
| * in the binding | |
| */ | |
| static inline bool ovpn_bind_skb_src_match(const struct ovpn_bind *bind, | |
| const struct sk_buff *skb) | |
| { | |
| const union ovpn_sockaddr *remote; | |
| if (unlikely(!bind)) | |
| return false; | |
| remote = &bind->remote; | |
| switch (skb->protocol) { | |
| case htons(ETH_P_IP): | |
| if (unlikely(remote->in4.sin_family != AF_INET)) | |
| return false; | |
| if (unlikely(remote->in4.sin_addr.s_addr != ip_hdr(skb)->saddr)) | |
| return false; | |
| if (unlikely(remote->in4.sin_port != udp_hdr(skb)->source)) | |
| return false; | |
| break; | |
| case htons(ETH_P_IPV6): | |
| if (unlikely(remote->in6.sin6_family != AF_INET6)) | |
| return false; | |
| if (unlikely(!ipv6_addr_equal(&remote->in6.sin6_addr, | |
| &ipv6_hdr(skb)->saddr))) | |
| return false; | |
| if (unlikely(remote->in6.sin6_port != udp_hdr(skb)->source)) | |
| return false; | |
| break; | |
| default: | |
| return false; | |
| } | |
| return true; | |
| } | |
| struct ovpn_bind *ovpn_bind_from_sockaddr(const struct sockaddr_storage *sa); | |
| void ovpn_bind_reset(struct ovpn_peer *peer, struct ovpn_bind *bind); | |
| #endif /* _NET_OVPN_OVPNBIND_H_ */ |