/** @file * @brief IPv6 and IPv4 definitions * * Generic IPv6 and IPv4 address definitions. */ /* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_NET_NET_IP_H_ #define ZEPHYR_INCLUDE_NET_NET_IP_H_ /** * @brief IPv4/IPv6 primitives and helpers * @defgroup ip_4_6 IPv4/IPv6 primitives and helpers * @ingroup networking * @{ */ #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** @cond INTERNAL_HIDDEN */ /* Specifying VLAN tag here in order to avoid circular dependencies */ #define NET_VLAN_TAG_UNSPEC 0x0fff /** @endcond */ /* Protocol families. */ #define PF_UNSPEC 0 /**< Unspecified protocol family. */ #define PF_INET 1 /**< IP protocol family version 4. */ #define PF_INET6 2 /**< IP protocol family version 6. */ #define PF_PACKET 3 /**< Packet family. */ #define PF_CAN 4 /**< Controller Area Network. */ #define PF_NET_MGMT 5 /**< Network management info. */ #define PF_LOCAL 6 /**< Inter-process communication */ #define PF_UNIX PF_LOCAL /**< Inter-process communication */ /* Address families. */ #define AF_UNSPEC PF_UNSPEC /**< Unspecified address family. */ #define AF_INET PF_INET /**< IP protocol family version 4. */ #define AF_INET6 PF_INET6 /**< IP protocol family version 6. */ #define AF_PACKET PF_PACKET /**< Packet family. */ #define AF_CAN PF_CAN /**< Controller Area Network. */ #define AF_NET_MGMT PF_NET_MGMT /**< Network management info. */ #define AF_LOCAL PF_LOCAL /**< Inter-process communication */ #define AF_UNIX PF_UNIX /**< Inter-process communication */ /** Protocol numbers from IANA/BSD */ enum net_ip_protocol { IPPROTO_IP = 0, /**< IP protocol (pseudo-val for setsockopt() */ IPPROTO_ICMP = 1, /**< ICMP protocol */ IPPROTO_IGMP = 2, /**< IGMP protocol */ IPPROTO_IPIP = 4, /**< IPIP tunnels */ IPPROTO_TCP = 6, /**< TCP protocol */ IPPROTO_UDP = 17, /**< UDP protocol */ IPPROTO_IPV6 = 41, /**< IPv6 protocol */ IPPROTO_ICMPV6 = 58, /**< ICMPv6 protocol */ IPPROTO_RAW = 255, /**< RAW IP packets */ }; /** Protocol numbers for TLS protocols */ enum net_ip_protocol_secure { IPPROTO_TLS_1_0 = 256, /**< TLS 1.0 protocol */ IPPROTO_TLS_1_1 = 257, /**< TLS 1.1 protocol */ IPPROTO_TLS_1_2 = 258, /**< TLS 1.2 protocol */ IPPROTO_DTLS_1_0 = 272, /**< DTLS 1.0 protocol */ IPPROTO_DTLS_1_2 = 273, /**< DTLS 1.2 protocol */ }; /** Socket type */ enum net_sock_type { SOCK_STREAM = 1, /**< Stream socket type */ SOCK_DGRAM, /**< Datagram socket type */ SOCK_RAW /**< RAW socket type */ }; /** @brief Convert 16-bit value from network to host byte order. * * @param x The network byte order value to convert. * * @return Host byte order value. */ #define ntohs(x) sys_be16_to_cpu(x) /** @brief Convert 32-bit value from network to host byte order. * * @param x The network byte order value to convert. * * @return Host byte order value. */ #define ntohl(x) sys_be32_to_cpu(x) /** @brief Convert 64-bit value from network to host byte order. * * @param x The network byte order value to convert. * * @return Host byte order value. */ #define ntohll(x) sys_be64_to_cpu(x) /** @brief Convert 16-bit value from host to network byte order. * * @param x The host byte order value to convert. * * @return Network byte order value. */ #define htons(x) sys_cpu_to_be16(x) /** @brief Convert 32-bit value from host to network byte order. * * @param x The host byte order value to convert. * * @return Network byte order value. */ #define htonl(x) sys_cpu_to_be32(x) /** @brief Convert 64-bit value from host to network byte order. * * @param x The host byte order value to convert. * * @return Network byte order value. */ #define htonll(x) sys_cpu_to_be64(x) /** IPv6 address struct */ struct in6_addr { union { uint8_t s6_addr[16]; uint16_t s6_addr16[8]; /* In big endian */ uint32_t s6_addr32[4]; /* In big endian */ }; }; /** IPv4 address struct */ struct in_addr { union { uint8_t s4_addr[4]; uint16_t s4_addr16[2]; /* In big endian */ uint32_t s4_addr32[1]; /* In big endian */ uint32_t s_addr; /* In big endian, for POSIX compatibility. */ }; }; /** Socket address family type */ typedef unsigned short int sa_family_t; /** Length of a socket address */ typedef size_t socklen_t; /* * Note that the sin_port and sin6_port are in network byte order * in various sockaddr* structs. */ /** Socket address struct for IPv6. */ struct sockaddr_in6 { sa_family_t sin6_family; /* AF_INET6 */ uint16_t sin6_port; /* Port number */ struct in6_addr sin6_addr; /* IPv6 address */ uint8_t sin6_scope_id; /* interfaces for a scope */ }; struct sockaddr_in6_ptr { sa_family_t sin6_family; /* AF_INET6 */ uint16_t sin6_port; /* Port number */ struct in6_addr *sin6_addr; /* IPv6 address */ uint8_t sin6_scope_id; /* interfaces for a scope */ }; /** Socket address struct for IPv4. */ struct sockaddr_in { sa_family_t sin_family; /* AF_INET */ uint16_t sin_port; /* Port number */ struct in_addr sin_addr; /* IPv4 address */ }; struct sockaddr_in_ptr { sa_family_t sin_family; /* AF_INET */ uint16_t sin_port; /* Port number */ struct in_addr *sin_addr; /* IPv4 address */ }; /** Socket address struct for packet socket. */ struct sockaddr_ll { sa_family_t sll_family; /* Always AF_PACKET */ uint16_t sll_protocol; /* Physical-layer protocol */ int sll_ifindex; /* Interface number */ uint16_t sll_hatype; /* ARP hardware type */ uint8_t sll_pkttype; /* Packet type */ uint8_t sll_halen; /* Length of address */ uint8_t sll_addr[8]; /* Physical-layer address */ }; struct sockaddr_ll_ptr { sa_family_t sll_family; /* Always AF_PACKET */ uint16_t sll_protocol; /* Physical-layer protocol */ int sll_ifindex; /* Interface number */ uint16_t sll_hatype; /* ARP hardware type */ uint8_t sll_pkttype; /* Packet type */ uint8_t sll_halen; /* Length of address */ uint8_t *sll_addr; /* Physical-layer address */ }; struct sockaddr_can_ptr { sa_family_t can_family; int can_ifindex; }; #if !defined(HAVE_IOVEC) struct iovec { void *iov_base; size_t iov_len; }; #endif struct msghdr { void *msg_name; /* optional socket address */ socklen_t msg_namelen; /* size of socket address */ struct iovec *msg_iov; /* scatter/gather array */ size_t msg_iovlen; /* number of elements in msg_iov */ void *msg_control; /* ancillary data */ size_t msg_controllen; /* ancillary data buffer len */ int msg_flags; /* flags on received message */ }; struct cmsghdr { socklen_t cmsg_len; /* Number of bytes, including header */ int cmsg_level; /* Originating protocol */ int cmsg_type; /* Protocol-specific type */ /* Flexible array member to force alignment of cmsghdr */ z_max_align_t cmsg_data[]; }; /* Alignment for headers and data. These are arch specific but define * them here atm if not found alredy. */ #if !defined(ALIGN_H) #define ALIGN_H(x) ROUND_UP(x, __alignof__(struct cmsghdr)) #endif #if !defined(ALIGN_D) #define ALIGN_D(x) ROUND_UP(x, __alignof__(z_max_align_t)) #endif #if !defined(CMSG_FIRSTHDR) #define CMSG_FIRSTHDR(msghdr) \ ((msghdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ (struct cmsghdr *)((msghdr)->msg_control) : NULL) #endif #if !defined(CMSG_NXTHDR) #define CMSG_NXTHDR(msghdr, cmsg) \ (((cmsg) == NULL) ? CMSG_FIRSTHDR(msghdr) : \ (((uint8_t *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) + \ ALIGN_D(sizeof(struct cmsghdr)) > \ (uint8_t *)((msghdr)->msg_control) + (msghdr)->msg_controllen) ? \ NULL : \ (struct cmsghdr *)((uint8_t *)(cmsg) + \ ALIGN_H((cmsg)->cmsg_len)))) #endif #if !defined(CMSG_DATA) #define CMSG_DATA(cmsg) ((uint8_t *)(cmsg) + ALIGN_D(sizeof(struct cmsghdr))) #endif #if !defined(CMSG_SPACE) #define CMSG_SPACE(length) (ALIGN_D(sizeof(struct cmsghdr)) + ALIGN_H(length)) #endif #if !defined(CMSG_LEN) #define CMSG_LEN(length) (ALIGN_D(sizeof(struct cmsghdr)) + length) #endif /** @cond INTERNAL_HIDDEN */ /* Packet types. */ #define PACKET_HOST 0 /* To us */ #define PACKET_BROADCAST 1 /* To all */ #define PACKET_MULTICAST 2 /* To group */ #define PACKET_OTHERHOST 3 /* To someone else */ #define PACKET_OUTGOING 4 /* Originated by us */ #define PACKET_LOOPBACK 5 #define PACKET_FASTROUTE 6 /* Note: These macros are defined in a specific order. * The largest sockaddr size is the last one. */ #if defined(CONFIG_NET_IPV4) #undef NET_SOCKADDR_MAX_SIZE #undef NET_SOCKADDR_PTR_MAX_SIZE #define NET_SOCKADDR_MAX_SIZE (sizeof(struct sockaddr_in)) #define NET_SOCKADDR_PTR_MAX_SIZE (sizeof(struct sockaddr_in_ptr)) #endif #if defined(CONFIG_NET_SOCKETS_PACKET) #undef NET_SOCKADDR_MAX_SIZE #undef NET_SOCKADDR_PTR_MAX_SIZE #define NET_SOCKADDR_MAX_SIZE (sizeof(struct sockaddr_ll)) #define NET_SOCKADDR_PTR_MAX_SIZE (sizeof(struct sockaddr_ll_ptr)) #endif #if defined(CONFIG_NET_IPV6) #undef NET_SOCKADDR_MAX_SIZE #define NET_SOCKADDR_MAX_SIZE (sizeof(struct sockaddr_in6)) #if !defined(CONFIG_NET_SOCKETS_PACKET) #undef NET_SOCKADDR_PTR_MAX_SIZE #define NET_SOCKADDR_PTR_MAX_SIZE (sizeof(struct sockaddr_in6_ptr)) #endif #endif #if !defined(CONFIG_NET_IPV4) #if !defined(CONFIG_NET_IPV6) #if !defined(CONFIG_NET_SOCKETS_PACKET) #define NET_SOCKADDR_MAX_SIZE (sizeof(struct sockaddr_in6)) #define NET_SOCKADDR_PTR_MAX_SIZE (sizeof(struct sockaddr_in6_ptr)) #endif #endif #endif /** @endcond */ /** Generic sockaddr struct. Must be cast to proper type. */ struct sockaddr { sa_family_t sa_family; char data[NET_SOCKADDR_MAX_SIZE - sizeof(sa_family_t)]; }; /** @cond INTERNAL_HIDDEN */ struct sockaddr_ptr { sa_family_t family; char data[NET_SOCKADDR_PTR_MAX_SIZE - sizeof(sa_family_t)]; }; /* Same as sockaddr in our case */ struct sockaddr_storage { sa_family_t ss_family; char data[NET_SOCKADDR_MAX_SIZE - sizeof(sa_family_t)]; }; /* Socket address struct for UNIX domain sockets */ struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[NET_SOCKADDR_MAX_SIZE - sizeof(sa_family_t)]; }; struct net_addr { sa_family_t family; union { struct in6_addr in6_addr; struct in_addr in_addr; }; }; #define IN6ADDR_ANY_INIT { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0 } } } #define IN6ADDR_LOOPBACK_INIT { { { 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 1 } } } extern const struct in6_addr in6addr_any; extern const struct in6_addr in6addr_loopback; /** @endcond */ /** Max length of the IPv4 address as a string. Defined by POSIX. */ #define INET_ADDRSTRLEN 16 /** Max length of the IPv6 address as a string. Takes into account possible * mapped IPv4 addresses. */ #define INET6_ADDRSTRLEN 46 /** @cond INTERNAL_HIDDEN */ /* These are for internal usage of the stack */ #define NET_IPV6_ADDR_LEN sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx") #define NET_IPV4_ADDR_LEN sizeof("xxx.xxx.xxx.xxx") #define INADDR_ANY 0 #define INADDR_ANY_INIT { { { INADDR_ANY } } } /** @endcond */ enum net_ip_mtu { /** IPv6 MTU length. We must be able to receive this size IPv6 packet * without fragmentation. */ NET_IPV6_MTU = 1280, /** IPv4 MTU length. We must be able to receive this size IPv4 packet * without fragmentation. */ NET_IPV4_MTU = 576, }; /** Network packet priority settings described in IEEE 802.1Q Annex I.1 */ enum net_priority { NET_PRIORITY_BK = 1, /**< Background (lowest) */ NET_PRIORITY_BE = 0, /**< Best effort (default) */ NET_PRIORITY_EE = 2, /**< Excellent effort */ NET_PRIORITY_CA = 3, /**< Critical applications (highest) */ NET_PRIORITY_VI = 4, /**< Video, < 100 ms latency and jitter */ NET_PRIORITY_VO = 5, /**< Voice, < 10 ms latency and jitter */ NET_PRIORITY_IC = 6, /**< Internetwork control */ NET_PRIORITY_NC = 7 /**< Network control */ } __packed; #define NET_MAX_PRIORITIES 8 /* How many priority values there are */ /** IPv6/IPv4 network connection tuple */ struct net_tuple { struct net_addr *remote_addr; /**< IPv6/IPv4 remote address */ struct net_addr *local_addr; /**< IPv6/IPv4 local address */ uint16_t remote_port; /**< UDP/TCP remote port */ uint16_t local_port; /**< UDP/TCP local port */ enum net_ip_protocol ip_proto; /**< IP protocol */ }; /** What is the current state of the network address */ enum net_addr_state { NET_ADDR_ANY_STATE = -1, /**< Default (invalid) address type */ NET_ADDR_TENTATIVE = 0, /**< Tentative address */ NET_ADDR_PREFERRED, /**< Preferred address */ NET_ADDR_DEPRECATED, /**< Deprecated address */ } __packed; /** How the network address is assigned to network interface */ enum net_addr_type { /** Default value. This is not a valid value. */ NET_ADDR_ANY = 0, /** Auto configured address */ NET_ADDR_AUTOCONF, /** Address is from DHCP */ NET_ADDR_DHCP, /** Manually set address */ NET_ADDR_MANUAL, /** Manually set address which is overridable by DHCP */ NET_ADDR_OVERRIDABLE, } __packed; /** @cond INTERNAL_HIDDEN */ struct net_ipv6_hdr { uint8_t vtc; uint8_t tcflow; uint16_t flow; uint16_t len; uint8_t nexthdr; uint8_t hop_limit; struct in6_addr src; struct in6_addr dst; } __packed; struct net_ipv6_frag_hdr { uint8_t nexthdr; uint8_t reserved; uint16_t offset; uint32_t id; } __packed; struct net_ipv4_hdr { uint8_t vhl; uint8_t tos; uint16_t len; uint8_t id[2]; uint8_t offset[2]; uint8_t ttl; uint8_t proto; uint16_t chksum; struct in_addr src; struct in_addr dst; } __packed; struct net_icmp_hdr { uint8_t type; uint8_t code; uint16_t chksum; } __packed; struct net_udp_hdr { uint16_t src_port; uint16_t dst_port; uint16_t len; uint16_t chksum; } __packed; struct net_tcp_hdr { uint16_t src_port; uint16_t dst_port; uint8_t seq[4]; uint8_t ack[4]; uint8_t offset; uint8_t flags; uint8_t wnd[2]; uint16_t chksum; uint8_t urg[2]; uint8_t optdata[0]; } __packed; static inline const char *net_addr_type2str(enum net_addr_type type) { switch (type) { case NET_ADDR_AUTOCONF: return "AUTO"; case NET_ADDR_DHCP: return "DHCP"; case NET_ADDR_MANUAL: return "MANUAL"; case NET_ADDR_OVERRIDABLE: return "OVERRIDE"; case NET_ADDR_ANY: default: break; } return ""; } /* IPv6 extension headers types */ #define NET_IPV6_NEXTHDR_HBHO 0 #define NET_IPV6_NEXTHDR_DESTO 60 #define NET_IPV6_NEXTHDR_ROUTING 43 #define NET_IPV6_NEXTHDR_FRAG 44 #define NET_IPV6_NEXTHDR_NONE 59 /** * This 2 unions are here temporarily, as long as net_context.h will * be still public and not part of the core only. */ union net_ip_header { struct net_ipv4_hdr *ipv4; struct net_ipv6_hdr *ipv6; }; union net_proto_header { struct net_udp_hdr *udp; struct net_tcp_hdr *tcp; }; #define NET_UDPH_LEN 8 /* Size of UDP header */ #define NET_TCPH_LEN 20 /* Size of TCP header */ #define NET_ICMPH_LEN 4 /* Size of ICMP header */ #define NET_IPV6H_LEN 40 /* Size of IPv6 header */ #define NET_ICMPV6H_LEN NET_ICMPH_LEN /* Size of ICMPv6 header */ #define NET_IPV6UDPH_LEN (NET_UDPH_LEN + NET_IPV6H_LEN) /* IPv6 + UDP */ #define NET_IPV6TCPH_LEN (NET_TCPH_LEN + NET_IPV6H_LEN) /* IPv6 + TCP */ #define NET_IPV6ICMPH_LEN (NET_IPV6H_LEN + NET_ICMPH_LEN) /* ICMPv6 + IPv6 */ #define NET_IPV6_FRAGH_LEN 8 #define NET_IPV4H_LEN 20 /* Size of IPv4 header */ #define NET_ICMPV4H_LEN NET_ICMPH_LEN /* Size of ICMPv4 header */ #define NET_IPV4UDPH_LEN (NET_UDPH_LEN + NET_IPV4H_LEN) /* IPv4 + UDP */ #define NET_IPV4TCPH_LEN (NET_TCPH_LEN + NET_IPV4H_LEN) /* IPv4 + TCP */ #define NET_IPV4ICMPH_LEN (NET_IPV4H_LEN + NET_ICMPH_LEN) /* ICMPv4 + IPv4 */ #define NET_IPV6H_LENGTH_OFFSET 0x04 /* Offset of the Length field in the IPv6 header */ #define NET_IPV6_FRAGH_OFFSET_MASK 0xfff8 /* Mask for the 13-bit Fragment Offset field */ /** @endcond */ /** * @brief Check if the IPv6 address is a loopback address (::1). * * @param addr IPv6 address * * @return True if address is a loopback address, False otherwise. */ static inline bool net_ipv6_is_addr_loopback(struct in6_addr *addr) { return UNALIGNED_GET(&addr->s6_addr32[0]) == 0 && UNALIGNED_GET(&addr->s6_addr32[1]) == 0 && UNALIGNED_GET(&addr->s6_addr32[2]) == 0 && ntohl(UNALIGNED_GET(&addr->s6_addr32[3])) == 1; } /** * @brief Check if the IPv6 address is a multicast address. * * @param addr IPv6 address * * @return True if address is multicast address, False otherwise. */ static inline bool net_ipv6_is_addr_mcast(const struct in6_addr *addr) { return addr->s6_addr[0] == 0xFF; } struct net_if; struct net_if_config; extern struct net_if_addr *net_if_ipv6_addr_lookup(const struct in6_addr *addr, struct net_if **iface); /** * @brief Check if IPv6 address is found in one of the network interfaces. * * @param addr IPv6 address * * @return True if address was found, False otherwise. */ static inline bool net_ipv6_is_my_addr(struct in6_addr *addr) { return net_if_ipv6_addr_lookup(addr, NULL) != NULL; } extern struct net_if_mcast_addr *net_if_ipv6_maddr_lookup( const struct in6_addr *addr, struct net_if **iface); /** * @brief Check if IPv6 multicast address is found in one of the * network interfaces. * * @param maddr Multicast IPv6 address * * @return True if address was found, False otherwise. */ static inline bool net_ipv6_is_my_maddr(struct in6_addr *maddr) { return net_if_ipv6_maddr_lookup(maddr, NULL) != NULL; } /** * @brief Check if two IPv6 addresses are same when compared after prefix mask. * * @param addr1 First IPv6 address. * @param addr2 Second IPv6 address. * @param length Prefix length (max length is 128). * * @return True if IPv6 prefixes are the same, False otherwise. */ static inline bool net_ipv6_is_prefix(const uint8_t *addr1, const uint8_t *addr2, uint8_t length) { uint8_t bits = 128 - length; uint8_t bytes = length / 8U; uint8_t remain = bits % 8; uint8_t mask; if (length > 128) { return false; } if (memcmp(addr1, addr2, bytes)) { return false; } if (!remain) { /* No remaining bits, the prefixes are the same as first * bytes are the same. */ return true; } /* Create a mask that has remaining most significant bits set */ mask = ((0xff << (8 - remain)) ^ 0xff) << remain; return (addr1[bytes] & mask) == (addr2[bytes] & mask); } /** * @brief Check if the IPv4 address is a loopback address (127.0.0.0/8). * * @param addr IPv4 address * * @return True if address is a loopback address, False otherwise. */ static inline bool net_ipv4_is_addr_loopback(struct in_addr *addr) { return addr->s4_addr[0] == 127U; } /** * @brief Check if the IPv4 address is unspecified (all bits zero) * * @param addr IPv4 address. * * @return True if the address is unspecified, false otherwise. */ static inline bool net_ipv4_is_addr_unspecified(const struct in_addr *addr) { return UNALIGNED_GET(&addr->s_addr) == 0; } /** * @brief Check if the IPv4 address is a multicast address. * * @param addr IPv4 address * * @return True if address is multicast address, False otherwise. */ static inline bool net_ipv4_is_addr_mcast(const struct in_addr *addr) { return (ntohl(UNALIGNED_GET(&addr->s_addr)) & 0xF0000000) == 0xE0000000; } /** * @brief Check if the given IPv4 address is a link local address. * * @param addr A valid pointer on an IPv4 address * * @return True if it is, false otherwise. */ static inline bool net_ipv4_is_ll_addr(const struct in_addr *addr) { return (ntohl(UNALIGNED_GET(&addr->s_addr)) & 0xA9FE0000) == 0xA9FE0000; } /** * @def net_ipaddr_copy * @brief Copy an IPv4 or IPv6 address * * @param dest Destination IP address. * @param src Source IP address. * * @return Destination address. */ #define net_ipaddr_copy(dest, src) \ UNALIGNED_PUT(UNALIGNED_GET(src), dest) /** * @brief Compare two IPv4 addresses * * @param addr1 Pointer to IPv4 address. * @param addr2 Pointer to IPv4 address. * * @return True if the addresses are the same, false otherwise. */ static inline bool net_ipv4_addr_cmp(const struct in_addr *addr1, const struct in_addr *addr2) { return UNALIGNED_GET(&addr1->s_addr) == UNALIGNED_GET(&addr2->s_addr); } /** * @brief Compare two IPv6 addresses * * @param addr1 Pointer to IPv6 address. * @param addr2 Pointer to IPv6 address. * * @return True if the addresses are the same, false otherwise. */ static inline bool net_ipv6_addr_cmp(const struct in6_addr *addr1, const struct in6_addr *addr2) { return !memcmp(addr1, addr2, sizeof(struct in6_addr)); } /** * @brief Check if the given IPv6 address is a link local address. * * @param addr A valid pointer on an IPv6 address * * @return True if it is, false otherwise. */ static inline bool net_ipv6_is_ll_addr(const struct in6_addr *addr) { return UNALIGNED_GET(&addr->s6_addr16[0]) == htons(0xFE80); } /** * @brief Check if the given IPv6 address is a unique local address. * * @param addr A valid pointer on an IPv6 address * * @return True if it is, false otherwise. */ static inline bool net_ipv6_is_ula_addr(const struct in6_addr *addr) { return addr->s6_addr[0] == 0xFD; } /** * @brief Return pointer to any (all bits zeros) IPv6 address. * * @return Any IPv6 address. */ const struct in6_addr *net_ipv6_unspecified_address(void); /** * @brief Return pointer to any (all bits zeros) IPv4 address. * * @return Any IPv4 address. */ const struct in_addr *net_ipv4_unspecified_address(void); /** * @brief Return pointer to broadcast (all bits ones) IPv4 address. * * @return Broadcast IPv4 address. */ const struct in_addr *net_ipv4_broadcast_address(void); struct net_if; extern bool net_if_ipv4_addr_mask_cmp(struct net_if *iface, const struct in_addr *addr); /** * @brief Check if the given address belongs to same subnet that * has been configured for the interface. * * @param iface A valid pointer on an interface * @param addr IPv4 address * * @return True if address is in same subnet, false otherwise. */ static inline bool net_ipv4_addr_mask_cmp(struct net_if *iface, const struct in_addr *addr) { return net_if_ipv4_addr_mask_cmp(iface, addr); } extern bool net_if_ipv4_is_addr_bcast(struct net_if *iface, const struct in_addr *addr); /** * @brief Check if the given IPv4 address is a broadcast address. * * @param iface Interface to use. Must be a valid pointer to an interface. * @param addr IPv4 address * * @return True if address is a broadcast address, false otherwise. */ #if defined(CONFIG_NET_NATIVE_IPV4) static inline bool net_ipv4_is_addr_bcast(struct net_if *iface, const struct in_addr *addr) { if (net_ipv4_addr_cmp(addr, net_ipv4_broadcast_address())) { return true; } return net_if_ipv4_is_addr_bcast(iface, addr); } #else static inline bool net_ipv4_is_addr_bcast(struct net_if *iface, const struct in_addr *addr) { ARG_UNUSED(iface); ARG_UNUSED(addr); return false; } #endif extern struct net_if_addr *net_if_ipv4_addr_lookup(const struct in_addr *addr, struct net_if **iface); /** * @brief Check if the IPv4 address is assigned to any network interface * in the system. * * @param addr A valid pointer on an IPv4 address * * @return True if IPv4 address is found in one of the network interfaces, * False otherwise. */ static inline bool net_ipv4_is_my_addr(const struct in_addr *addr) { bool ret; ret = net_if_ipv4_addr_lookup(addr, NULL) != NULL; if (!ret) { ret = net_ipv4_is_addr_bcast(NULL, addr); } return ret; } /** * @brief Check if the IPv6 address is unspecified (all bits zero) * * @param addr IPv6 address. * * @return True if the address is unspecified, false otherwise. */ static inline bool net_ipv6_is_addr_unspecified(const struct in6_addr *addr) { return UNALIGNED_GET(&addr->s6_addr32[0]) == 0 && UNALIGNED_GET(&addr->s6_addr32[1]) == 0 && UNALIGNED_GET(&addr->s6_addr32[2]) == 0 && UNALIGNED_GET(&addr->s6_addr32[3]) == 0; } /** * @brief Check if the IPv6 address is solicited node multicast address * FF02:0:0:0:0:1:FFXX:XXXX defined in RFC 3513 * * @param addr IPv6 address. * * @return True if the address is solicited node address, false otherwise. */ static inline bool net_ipv6_is_addr_solicited_node(const struct in6_addr *addr) { return UNALIGNED_GET(&addr->s6_addr32[0]) == htonl(0xff020000) && UNALIGNED_GET(&addr->s6_addr32[1]) == 0x00000000 && UNALIGNED_GET(&addr->s6_addr32[2]) == htonl(0x00000001) && ((UNALIGNED_GET(&addr->s6_addr32[3]) & htonl(0xff000000)) == htonl(0xff000000)); } /** * @brief Check if the IPv6 address is a given scope multicast * address (FFyx::). * * @param addr IPv6 address * @param scope Scope to check * * @return True if the address is in given scope multicast address, * false otherwise. */ static inline bool net_ipv6_is_addr_mcast_scope(const struct in6_addr *addr, int scope) { return (addr->s6_addr[0] == 0xff) && (addr->s6_addr[1] == scope); } /** * @brief Check if the IPv6 addresses have the same multicast scope (FFyx::). * * @param addr_1 IPv6 address 1 * @param addr_2 IPv6 address 2 * * @return True if both addresses have same multicast scope, * false otherwise. */ static inline bool net_ipv6_is_same_mcast_scope(const struct in6_addr *addr_1, const struct in6_addr *addr_2) { return (addr_1->s6_addr[0] == 0xff) && (addr_2->s6_addr[0] == 0xff) && (addr_1->s6_addr[1] == addr_2->s6_addr[1]); } /** * @brief Check if the IPv6 address is a global multicast address (FFxE::/16). * * @param addr IPv6 address. * * @return True if the address is global multicast address, false otherwise. */ static inline bool net_ipv6_is_addr_mcast_global(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_scope(addr, 0x0e); } /** * @brief Check if the IPv6 address is a interface scope multicast * address (FFx1::). * * @param addr IPv6 address. * * @return True if the address is a interface scope multicast address, * false otherwise. */ static inline bool net_ipv6_is_addr_mcast_iface(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_scope(addr, 0x01); } /** * @brief Check if the IPv6 address is a link local scope multicast * address (FFx2::). * * @param addr IPv6 address. * * @return True if the address is a link local scope multicast address, * false otherwise. */ static inline bool net_ipv6_is_addr_mcast_link(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_scope(addr, 0x02); } /** * @brief Check if the IPv6 address is a mesh-local scope multicast * address (FFx3::). * * @param addr IPv6 address. * * @return True if the address is a mesh-local scope multicast address, * false otherwise. */ static inline bool net_ipv6_is_addr_mcast_mesh(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_scope(addr, 0x03); } /** * @brief Check if the IPv6 address is a site scope multicast * address (FFx5::). * * @param addr IPv6 address. * * @return True if the address is a site scope multicast address, * false otherwise. */ static inline bool net_ipv6_is_addr_mcast_site(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_scope(addr, 0x05); } /** * @brief Check if the IPv6 address is an organization scope multicast * address (FFx8::). * * @param addr IPv6 address. * * @return True if the address is an organization scope multicast address, * false otherwise. */ static inline bool net_ipv6_is_addr_mcast_org(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_scope(addr, 0x08); } /** * @brief Check if the IPv6 address belongs to certain multicast group * * @param addr IPv6 address. * @param group Group id IPv6 address, the values must be in network * byte order * * @return True if the IPv6 multicast address belongs to given multicast * group, false otherwise. */ static inline bool net_ipv6_is_addr_mcast_group(const struct in6_addr *addr, const struct in6_addr *group) { return UNALIGNED_GET(&addr->s6_addr16[1]) == group->s6_addr16[1] && UNALIGNED_GET(&addr->s6_addr16[2]) == group->s6_addr16[2] && UNALIGNED_GET(&addr->s6_addr16[3]) == group->s6_addr16[3] && UNALIGNED_GET(&addr->s6_addr32[1]) == group->s6_addr32[1] && UNALIGNED_GET(&addr->s6_addr32[2]) == group->s6_addr32[1] && UNALIGNED_GET(&addr->s6_addr32[3]) == group->s6_addr32[3]; } /** * @brief Check if the IPv6 address belongs to the all nodes multicast group * * @param addr IPv6 address * * @return True if the IPv6 multicast address belongs to the all nodes multicast * group, false otherwise */ static inline bool net_ipv6_is_addr_mcast_all_nodes_group(const struct in6_addr *addr) { static const struct in6_addr all_nodes_mcast_group = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }; return net_ipv6_is_addr_mcast_group(addr, &all_nodes_mcast_group); } /** * @brief Check if the IPv6 address is a interface scope all nodes multicast * address (FF01::1). * * @param addr IPv6 address. * * @return True if the address is a interface scope all nodes multicast address, * false otherwise. */ static inline bool net_ipv6_is_addr_mcast_iface_all_nodes(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_iface(addr) && net_ipv6_is_addr_mcast_all_nodes_group(addr); } /** * @brief Check if the IPv6 address is a link local scope all nodes multicast * address (FF02::1). * * @param addr IPv6 address. * * @return True if the address is a link local scope all nodes multicast * address, false otherwise. */ static inline bool net_ipv6_is_addr_mcast_link_all_nodes(const struct in6_addr *addr) { return net_ipv6_is_addr_mcast_link(addr) && net_ipv6_is_addr_mcast_all_nodes_group(addr); } /** * @brief Create solicited node IPv6 multicast address * FF02:0:0:0:0:1:FFXX:XXXX defined in RFC 3513 * * @param src IPv6 address. * @param dst IPv6 address. */ static inline void net_ipv6_addr_create_solicited_node(const struct in6_addr *src, struct in6_addr *dst) { dst->s6_addr[0] = 0xFF; dst->s6_addr[1] = 0x02; UNALIGNED_PUT(0, &dst->s6_addr16[1]); UNALIGNED_PUT(0, &dst->s6_addr16[2]); UNALIGNED_PUT(0, &dst->s6_addr16[3]); UNALIGNED_PUT(0, &dst->s6_addr16[4]); dst->s6_addr[10] = 0U; dst->s6_addr[11] = 0x01; dst->s6_addr[12] = 0xFF; dst->s6_addr[13] = src->s6_addr[13]; UNALIGNED_PUT(UNALIGNED_GET(&src->s6_addr16[7]), &dst->s6_addr16[7]); } /** @brief Construct an IPv6 address from eight 16-bit words. * * @param addr IPv6 address * @param addr0 16-bit word which is part of the address * @param addr1 16-bit word which is part of the address * @param addr2 16-bit word which is part of the address * @param addr3 16-bit word which is part of the address * @param addr4 16-bit word which is part of the address * @param addr5 16-bit word which is part of the address * @param addr6 16-bit word which is part of the address * @param addr7 16-bit word which is part of the address */ static inline void net_ipv6_addr_create(struct in6_addr *addr, uint16_t addr0, uint16_t addr1, uint16_t addr2, uint16_t addr3, uint16_t addr4, uint16_t addr5, uint16_t addr6, uint16_t addr7) { UNALIGNED_PUT(htons(addr0), &addr->s6_addr16[0]); UNALIGNED_PUT(htons(addr1), &addr->s6_addr16[1]); UNALIGNED_PUT(htons(addr2), &addr->s6_addr16[2]); UNALIGNED_PUT(htons(addr3), &addr->s6_addr16[3]); UNALIGNED_PUT(htons(addr4), &addr->s6_addr16[4]); UNALIGNED_PUT(htons(addr5), &addr->s6_addr16[5]); UNALIGNED_PUT(htons(addr6), &addr->s6_addr16[6]); UNALIGNED_PUT(htons(addr7), &addr->s6_addr16[7]); } /** * @brief Create link local allnodes multicast IPv6 address * * @param addr IPv6 address */ static inline void net_ipv6_addr_create_ll_allnodes_mcast(struct in6_addr *addr) { net_ipv6_addr_create(addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0001); } /** * @brief Create link local allrouters multicast IPv6 address * * @param addr IPv6 address */ static inline void net_ipv6_addr_create_ll_allrouters_mcast(struct in6_addr *addr) { net_ipv6_addr_create(addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0002); } /** * @brief Create IPv6 address interface identifier * * @param addr IPv6 address * @param lladdr Link local address */ static inline void net_ipv6_addr_create_iid(struct in6_addr *addr, struct net_linkaddr *lladdr) { UNALIGNED_PUT(htonl(0xfe800000), &addr->s6_addr32[0]); UNALIGNED_PUT(0, &addr->s6_addr32[1]); switch (lladdr->len) { case 2: /* The generated IPv6 shall not toggle the * Universal/Local bit. RFC 6282 ch 3.2.2 */ if (lladdr->type == NET_LINK_IEEE802154 || lladdr->type == NET_LINK_CANBUS) { UNALIGNED_PUT(0, &addr->s6_addr32[2]); addr->s6_addr[11] = 0xff; addr->s6_addr[12] = 0xfe; addr->s6_addr[13] = 0U; addr->s6_addr[14] = lladdr->addr[0]; addr->s6_addr[15] = lladdr->addr[1]; } break; case 6: /* We do not toggle the Universal/Local bit * in Bluetooth. See RFC 7668 ch 3.2.2 */ memcpy(&addr->s6_addr[8], lladdr->addr, 3); addr->s6_addr[11] = 0xff; addr->s6_addr[12] = 0xfe; memcpy(&addr->s6_addr[13], lladdr->addr + 3, 3); #if defined(CONFIG_NET_L2_BT_ZEP1656) /* Workaround against older Linux kernel BT IPSP code. * This will be removed eventually. */ if (lladdr->type == NET_LINK_BLUETOOTH) { addr->s6_addr[8] ^= 0x02; } #endif if (lladdr->type == NET_LINK_ETHERNET) { addr->s6_addr[8] ^= 0x02; } break; case 8: memcpy(&addr->s6_addr[8], lladdr->addr, lladdr->len); addr->s6_addr[8] ^= 0x02; break; } } /** * @brief Check if given address is based on link layer address * * @return True if it is, False otherwise */ static inline bool net_ipv6_addr_based_on_ll(const struct in6_addr *addr, const struct net_linkaddr *lladdr) { if (!addr || !lladdr) { return false; } switch (lladdr->len) { case 2: if (!memcmp(&addr->s6_addr[14], lladdr->addr, lladdr->len) && addr->s6_addr[8] == 0U && addr->s6_addr[9] == 0U && addr->s6_addr[10] == 0U && addr->s6_addr[11] == 0xff && addr->s6_addr[12] == 0xfe) { return true; } break; case 6: if (lladdr->type == NET_LINK_ETHERNET) { if (!memcmp(&addr->s6_addr[9], &lladdr->addr[1], 2) && !memcmp(&addr->s6_addr[13], &lladdr->addr[3], 3) && addr->s6_addr[11] == 0xff && addr->s6_addr[12] == 0xfe && (addr->s6_addr[8] ^ 0x02) == lladdr->addr[0]) { return true; } } else if (lladdr->type == NET_LINK_BLUETOOTH) { if (!memcmp(&addr->s6_addr[9], &lladdr->addr[1], 2) && !memcmp(&addr->s6_addr[13], &lladdr->addr[3], 3) && addr->s6_addr[11] == 0xff && addr->s6_addr[12] == 0xfe #if defined(CONFIG_NET_L2_BT_ZEP1656) /* Workaround against older Linux kernel BT IPSP * code. This will be removed eventually. */ && (addr->s6_addr[8] ^ 0x02) == lladdr->addr[0] #endif ) { return true; } } break; case 8: if (!memcmp(&addr->s6_addr[9], &lladdr->addr[1], lladdr->len - 1) && (addr->s6_addr[8] ^ 0x02) == lladdr->addr[0]) { return true; } break; } return false; } /** * @brief Get sockaddr_in6 from sockaddr. This is a helper so that * the code calling this function can be made shorter. * * @param addr Socket address * * @return Pointer to IPv6 socket address */ static inline struct sockaddr_in6 *net_sin6(const struct sockaddr *addr) { return (struct sockaddr_in6 *)addr; } /** * @brief Get sockaddr_in from sockaddr. This is a helper so that * the code calling this function can be made shorter. * * @param addr Socket address * * @return Pointer to IPv4 socket address */ static inline struct sockaddr_in *net_sin(const struct sockaddr *addr) { return (struct sockaddr_in *)addr; } /** * @brief Get sockaddr_in6_ptr from sockaddr_ptr. This is a helper so that * the code calling this function can be made shorter. * * @param addr Socket address * * @return Pointer to IPv6 socket address */ static inline struct sockaddr_in6_ptr *net_sin6_ptr(const struct sockaddr_ptr *addr) { return (struct sockaddr_in6_ptr *)addr; } /** * @brief Get sockaddr_in_ptr from sockaddr_ptr. This is a helper so that * the code calling this function can be made shorter. * * @param addr Socket address * * @return Pointer to IPv4 socket address */ static inline struct sockaddr_in_ptr *net_sin_ptr(const struct sockaddr_ptr *addr) { return (struct sockaddr_in_ptr *)addr; } /** * @brief Get sockaddr_ll_ptr from sockaddr_ptr. This is a helper so that * the code calling this function can be made shorter. * * @param addr Socket address * * @return Pointer to linklayer socket address */ static inline struct sockaddr_ll_ptr *net_sll_ptr(const struct sockaddr_ptr *addr) { return (struct sockaddr_ll_ptr *)addr; } /** * @brief Get sockaddr_can_ptr from sockaddr_ptr. This is a helper so that * the code needing this functionality can be made shorter. * * @param addr Socket address * * @return Pointer to CAN socket address */ static inline struct sockaddr_can_ptr *net_can_ptr(const struct sockaddr_ptr *addr) { return (struct sockaddr_can_ptr *)addr; } /** * @brief Convert a string to IP address. * * @param family IP address family (AF_INET or AF_INET6) * @param src IP address in a null terminated string * @param dst Pointer to struct in_addr if family is AF_INET or * pointer to struct in6_addr if family is AF_INET6 * * @note This function doesn't do precise error checking, * do not use for untrusted strings. * * @return 0 if ok, < 0 if error */ __syscall int net_addr_pton(sa_family_t family, const char *src, void *dst); /** * @brief Convert IP address to string form. * * @param family IP address family (AF_INET or AF_INET6) * @param src Pointer to struct in_addr if family is AF_INET or * pointer to struct in6_addr if family is AF_INET6 * @param dst Buffer for IP address as a null terminated string * @param size Number of bytes available in the buffer * * @return dst pointer if ok, NULL if error */ __syscall char *net_addr_ntop(sa_family_t family, const void *src, char *dst, size_t size); /** * @brief Parse a string that contains either IPv4 or IPv6 address * and optional port, and store the information in user supplied * sockaddr struct. * * @details Syntax of the IP address string: * 192.0.2.1:80 * 192.0.2.42 * [2001:db8::1]:8080 * [2001:db8::2] * 2001:db::42 * Note that the str_len parameter is used to restrict the amount of * characters that are checked. If the string does not contain port * number, then the port number in sockaddr is not modified. * * @param str String that contains the IP address. * @param str_len Length of the string to be parsed. * @param addr Pointer to user supplied struct sockaddr. * * @return True if parsing could be done, false otherwise. */ bool net_ipaddr_parse(const char *str, size_t str_len, struct sockaddr *addr); /** * @brief Compare TCP sequence numbers. * * @details This function compares TCP sequence numbers, * accounting for wraparound effects. * * @param seq1 First sequence number * @param seq2 Seconds sequence number * * @return < 0 if seq1 < seq2, 0 if seq1 == seq2, > 0 if seq > seq2 */ static inline int32_t net_tcp_seq_cmp(uint32_t seq1, uint32_t seq2) { return (int32_t)(seq1 - seq2); } /** * @brief Check that one TCP sequence number is greater. * * @details This is convenience function on top of net_tcp_seq_cmp(). * * @param seq1 First sequence number * @param seq2 Seconds sequence number * * @return True if seq > seq2 */ static inline bool net_tcp_seq_greater(uint32_t seq1, uint32_t seq2) { return net_tcp_seq_cmp(seq1, seq2) > 0; } /** * @brief Convert a string of hex values to array of bytes. * * @details The syntax of the string is "ab:02:98:fa:42:01" * * @param buf Pointer to memory where the bytes are written. * @param buf_len Length of the memory area. * @param src String of bytes. * * @return 0 if ok, <0 if error */ int net_bytes_from_str(uint8_t *buf, int buf_len, const char *src); /** * @brief Convert Tx network packet priority to traffic class so we can place * the packet into correct Tx queue. * * @param prio Network priority * * @return Tx traffic class that handles that priority network traffic. */ int net_tx_priority2tc(enum net_priority prio); /** * @brief Convert Rx network packet priority to traffic class so we can place * the packet into correct Rx queue. * * @param prio Network priority * * @return Rx traffic class that handles that priority network traffic. */ int net_rx_priority2tc(enum net_priority prio); /** * @brief Convert network packet VLAN priority to network packet priority so we * can place the packet into correct queue. * * @param priority VLAN priority * * @return Network priority */ static inline enum net_priority net_vlan2priority(uint8_t priority) { /* Map according to IEEE 802.1Q */ static const uint8_t vlan2priority[] = { NET_PRIORITY_BE, NET_PRIORITY_BK, NET_PRIORITY_EE, NET_PRIORITY_CA, NET_PRIORITY_VI, NET_PRIORITY_VO, NET_PRIORITY_IC, NET_PRIORITY_NC }; if (priority >= ARRAY_SIZE(vlan2priority)) { /* Use Best Effort as the default priority */ return NET_PRIORITY_BE; } return (enum net_priority)vlan2priority[priority]; } /** * @brief Convert network packet priority to network packet VLAN priority. * * @param priority Packet priority * * @return VLAN priority (PCP) */ static inline uint8_t net_priority2vlan(enum net_priority priority) { /* The conversion works both ways */ return (uint8_t)net_vlan2priority(priority); } /** * @brief Return network address family value as a string. This is only usable * for debugging. * * @param family Network address family code * * @return Network address family as a string, or NULL if family is unknown. */ const char *net_family2str(sa_family_t family); #ifdef __cplusplus } #endif #include /** * @} */ #endif /* ZEPHYR_INCLUDE_NET_NET_IP_H_ */