aboutgitcodebugslistschat
path: root/inany.h
diff options
context:
space:
mode:
Diffstat (limited to 'inany.h')
-rw-r--r--inany.h68
1 files changed, 68 insertions, 0 deletions
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 <david@gibson.dropbear.id.au>
+ *
+ * inany.h - Types and helpers for handling addresses which could be
+ * IPv6 or IPv4 (encoded as IPv4-mapped IPv6 addresses)
+ */
+
+#include <assert.h>
+
+/** 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);
+ }
+}