From ca69c3f1964846b27f8333cd06f7594289cbf53b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 17 Nov 2022 16:58:55 +1100 Subject: inany: Helper functions for handling addresses which could be IPv4 or IPv6 struct tcp_conn stores an address which could be IPv6 or IPv4 using a union. We can do this without an additional tag by encoding IPv4 addresses as IPv4-mapped IPv6 addresses. This approach is useful wider than the specific place in tcp_conn, so expose a new 'union inany_addr' like this from a new inany.h. Along with that create a number of helper functions to make working with these "inany" addresses easier. Signed-off-by: David Gibson Signed-off-by: Stefano Brivio --- inany.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 inany.h (limited to 'inany.h') diff --git a/inany.h b/inany.h new file mode 100644 index 0000000..03e3e3f --- /dev/null +++ b/inany.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later + * Copyright Red Hat + * Author: David Gibson + * + * inany.h - Types and helpers for handling addresses which could be + * IPv6 or IPv4 (encoded as IPv4-mapped IPv6 addresses) + */ + +#include + +/** union inany_addr - Represents either an IPv4 or IPv6 address + * @a6: Address as an IPv6 address, may be IPv4-mapped + * @v4mapped.zero: All zero-bits for an IPv4 address + * @v4mapped.one: All one-bits for an IPv4 address + * @v4mapped.a4: If @a6 is an IPv4 mapped address, the IPv4 address + * + * @v4mapped shouldn't be accessed except via helpers. + */ +union inany_addr { + struct in6_addr a6; + struct { + uint8_t zero[10]; + uint8_t one[2]; + struct in_addr a4; + } v4mapped; +}; + +/** inany_v4 - Extract IPv4 address, if present, from IPv[46] address + * @addr: IPv4 or IPv6 address + * + * Return: IPv4 address if @addr is IPv4, NULL otherwise + */ +static inline const struct in_addr *inany_v4(const union inany_addr *addr) +{ + if (!IN6_IS_ADDR_V4MAPPED(&addr->a6)) + return NULL; + return &addr->v4mapped.a4; +} + +/** inany_equals - Compare two IPv[46] addresses + * @a, @b: IPv[46] addresses + * + * Return: true if @a and @b are the same address + */ +static inline bool inany_equals(const union inany_addr *a, + const union inany_addr *b) +{ + return IN6_ARE_ADDR_EQUAL(&a->a6, &b->a6); +} + +/** inany_from_af - Set IPv[46] address from IPv4 or IPv6 address + * @aa: Pointer to store IPv[46] address + * @af: Address family of @addr + * @addr: struct in_addr (IPv4) or struct in6_addr (IPv6) + */ +static inline void inany_from_af(union inany_addr *aa, int af, const void *addr) +{ + if (af == AF_INET6) { + aa->a6 = *((struct in6_addr *)addr); + } else if (af == AF_INET) { + memset(&aa->v4mapped.zero, 0, sizeof(aa->v4mapped.zero)); + memset(&aa->v4mapped.one, 0xff, sizeof(aa->v4mapped.one)); + aa->v4mapped.a4 = *((struct in_addr *)addr); + } else { + /* Not valid to call with other address families */ + assert(0); + } +} -- cgit v1.2.3