| /* 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_ */ |