You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
5.5 KiB
C

// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/ip.h
*
* Internet Protocol (IP) definitions and types.
*
* \copyright The DoubleFourteen Code Forge (C) All Right Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_IP_H_
#define DF_SYS_IP_H_
#include "xpt.h"
/// Known Internet Protocol address family types enumeration.
typedef enum {
IP4, ///< Internet Protocol version 4
IP6 ///< Internet Protocol version 6
} IpType;
/// Internet Protocol version 4 (IPv4) address, big endian order.
typedef union {
Uint8 bytes[4]; ///< Address bytes representation
Uint16 words[2]; ///< Address as a pair of 16-bits words
Uint32 dword; ///< Address as a single 32-bits dword (big endian)
} Ipv4adr;
/// Size of an IPv4 address in bytes.
#define IPV4_SIZE 4
/// Bits inside an IPv4 address.
#define IPV4_WIDTH (IPV4_SIZE * 8)
STATIC_ASSERT(sizeof(Ipv4adr) == IPV4_SIZE, "Bad Ipv4adr size");
/// Size of a string to make an IPv4 address, **excluding** trailing `\0`.
#define IPV4_STRLEN 16
/// IPv4 wildcard address static initializer: `0.0.0.0`.
#define IPV4_ANY_INIT { { 0x00, 0x00, 0x00, 0x00 } }
/// IPv4 loopback address static initializer: `127.0.0.1`.
#define IPV4_LOOPBACK_INIT { { 0x7f, 0x00, 0x00, 0x01 } }
/// IPv4 broadcast address static initializer: `255.255.255.255`.
#define IPV4_BROADCAST_INIT { { 0xff, 0xff, 0xff, 0xff } }
/**
* \brief Convert `Ipv4adr` to its string representation.
*
* The destination buffer **is assumed to be large enough to store
* the resulting string**, a buffer of `IPV4_STRLEN + 1`
* chars is safe to use as the `dest` argument.
*
* \param [in] adr Address to be converted, must not be `NULL`
* \param [out] dest Destination storage for string representation, must not be `NULL`
*
* \return Pointer to the trailing `\0` `char` inside `dest`, useful
* for further string concatenation.
*/
char *Ipv4_AdrToString(const Ipv4adr *adr, char *dest);
/**
* \brief Convert an address from its string representation to `Ipv4adr`.
*
* \return `OK` if conversion was successful, `NG` if address string
* does not represent a valid IP.
*/
Judgement Ipv4_StringToAdr(const char *address, Ipv4adr *dest);
/// Compare IPv4 addresses for equality.
FORCE_INLINE Boolean Ipv4_Equal(const Ipv4adr *a, const Ipv4adr *b)
{
return a->dword == b->dword;
}
/// Internet Protocol version 6 address.
typedef union {
Uint8 bytes[16]; ///< Address as raw bytes
Uint16 words[8]; ///< Address as short words sequence
Uint32 dwords[4]; ///< Address as dwords sequence
} Ipv6adr;
/// Size of an IPv6 address in bytes.
#define IPV6_SIZE 16
/// Bits inside an IPv6 address.
#define IPV6_WIDTH (IPV6_SIZE * 8)
STATIC_ASSERT(sizeof(Ipv6adr) == IPV6_SIZE, "Bad Ipv6adr size");
/// Size of a string to make an IPv6 address, **excluding** trailing `\0`.
#define IPV6_STRLEN 46
/// Static initializer for an UNSPECIFIED Ipv6 address.
#define IPV6_UNSPEC_INIT { { \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \
} }
/// Static initializer for a LOOPBACK Ipv6 address.
#define IPV6_LOOPBACK_INIT { { \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 \
} }
/// Test whether an IPv6 address represents a mapped IPv4 address.
#define IS_IPV6_V4MAPPED(v6) \
((v6)->dwords[0] == 0 && \
(v6)->dwords[1] == 0 && \
(v6)->dwords[2] == BE32(0xffff))
/// Test whether an IPv6 address is multicast.
#define IS_IPV6_MULTICAST(v6) ((v6)->bytes[0] == 0xff)
/**
* \brief Convert an IPv6 address to its string representation, destination
* storage should be `[IPV6_STRLEN + 1]`.
*
* \return Pointer to the trailing `\0` inside `dest`.
*/
char *Ipv6_AdrToString(const Ipv6adr *adr, char *dest);
/**
* \brief Convert IPv6 address string to `Ipv6adr`.
*
* \return `OK` on success, `NG` if `address` does not represent a valid IPv6 address.
*/
Judgement Ipv6_StringToAdr(const char *address, Ipv6adr *dest);
/// Compare two IPv6 addresses for equality.
FORCE_INLINE Boolean Ipv6_Equal(const Ipv6adr *a, const Ipv6adr *b)
{
return a->dwords[0] == b->dwords[0] && a->dwords[1] == b->dwords[1] &&
a->dwords[2] == b->dwords[2] && a->dwords[3] == b->dwords[3];
}
/// Generic IP address.
typedef struct {
IpType family; ///< Currently stored address family
union {
Uint8 bytes[IPV6_SIZE]; ///< Address as raw bytes, for convenient initialization
Ipv4adr v4; ///< IPv4 address, if `family == IP4`
Ipv6adr v6; ///< IPv6 address, if `family == IP6`
Uint32 dword; ///< As IPv4 single dword, for macro compat
Uint16 words[8]; ///< As IPv4/IPv6 word sequence, for macro compat
Uint32 dwords[4]; ///< As IPv6 dwords sequence, for macro compat
};
} Ipadr;
/**
* \brief Convert a generic IP address to its string representation.
*
* \note A destination string of length `IPV6_STRLEN + 1`
* is capable of storing an address string for any address family.
*/
char *Ip_AdrToString(const Ipadr *adr, char *dest);
/**
* \brief Convert IP string representation to `Ipadr`.
*
* \return `OK` on success, `NG` if `address` is not a valid IP address.
*/
Judgement Ip_StringToAdr(const char *address, Ipadr *dest);
/// Compare generic addresses for equality.
FORCE_INLINE Boolean Ip_Equal(const Ipadr *a, const Ipadr *b)
{
if (a->family != b->family)
return FALSE;
switch (a->family) {
case IP4: return Ipv4_Equal(&a->v4, &b->v4);
case IP6: return Ipv6_Equal(&a->v6, &b->v6);
default: UNREACHABLE; return FALSE;
}
}
#endif