/*
 * Copyright (c) 2016 Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief Public API for network interface
 */

#ifndef ZEPHYR_INCLUDE_NET_NET_IF_H_
#define ZEPHYR_INCLUDE_NET_NET_IF_H_

/**
 * @brief Network Interface abstraction layer
 * @defgroup net_if Network Interface abstraction layer
 * @ingroup networking
 * @{
 */

#include <device.h>
#include <sys/slist.h>

#include <net/net_core.h>
#include <net/hostname.h>
#include <net/net_linkaddr.h>
#include <net/net_ip.h>
#include <net/net_l2.h>
#include <net/net_stats.h>
#include <net/net_timeout.h>

#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4)
#include <net/dhcpv4.h>
#endif
#if defined(CONFIG_NET_IPV4_AUTO) && defined(CONFIG_NET_NATIVE_IPV4)
#include <net/ipv4_autoconf.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Network Interface unicast IP addresses
 *
 * Stores the unicast IP addresses assigned to this network interface.
 */
struct net_if_addr {
	/** IP address */
	struct net_addr address;

#if defined(CONFIG_NET_NATIVE_IPV6)
	struct net_timeout lifetime;
#endif

#if defined(CONFIG_NET_IPV6_DAD) && defined(CONFIG_NET_NATIVE_IPV6)
	/** Duplicate address detection (DAD) timer */
	sys_snode_t dad_node;
	uint32_t dad_start;
#endif
	/** How the IP address was set */
	enum net_addr_type addr_type;

	/** What is the current state of the address */
	enum net_addr_state addr_state;

#if defined(CONFIG_NET_IPV6_DAD) && defined(CONFIG_NET_NATIVE_IPV6)
	/** How many times we have done DAD */
	uint8_t dad_count;
#endif

	/** Is the IP address valid forever */
	uint8_t is_infinite : 1;

	/** Is this IP address used or not */
	uint8_t is_used : 1;

	/** Is this IP address usage limited to the subnet (mesh) or not */
	uint8_t is_mesh_local : 1;

	uint8_t _unused : 5;
};

/**
 * @brief Network Interface multicast IP addresses
 *
 * Stores the multicast IP addresses assigned to this network interface.
 */
struct net_if_mcast_addr {
	/** IP address */
	struct net_addr address;

	/** Is this multicast IP address used or not */
	uint8_t is_used : 1;

	/** Did we join to this group */
	uint8_t is_joined : 1;

	uint8_t _unused : 6;
};

/**
 * @brief Network Interface IPv6 prefixes
 *
 * Stores the multicast IP addresses assigned to this network interface.
 */
struct net_if_ipv6_prefix {
	/** Prefix lifetime */
	struct net_timeout lifetime;

	/** IPv6 prefix */
	struct in6_addr prefix;

	/** Backpointer to network interface where this prefix is used */
	struct net_if *iface;

	/** Prefix length */
	uint8_t len;

	/** Is the IP prefix valid forever */
	uint8_t is_infinite : 1;

	/** Is this prefix used or not */
	uint8_t is_used : 1;

	uint8_t _unused : 6;
};

/**
 * @brief Information about routers in the system.
 *
 * Stores the router information.
 */
struct net_if_router {
	/** Slist lifetime timer node */
	sys_snode_t node;

	/** IP address */
	struct net_addr address;

	/** Network interface the router is connected to */
	struct net_if *iface;

	/** Router life timer start */
	uint32_t life_start;

	/** Router lifetime */
	uint16_t lifetime;

	/** Is this router used or not */
	uint8_t is_used : 1;

	/** Is default router */
	uint8_t is_default : 1;

	/** Is the router valid forever */
	uint8_t is_infinite : 1;

	uint8_t _unused : 5;
};

enum net_if_flag {
	/** Interface is up/ready to receive and transmit */
	NET_IF_UP,

	/** Interface is pointopoint */
	NET_IF_POINTOPOINT,

	/** Interface is in promiscuous mode */
	NET_IF_PROMISC,

	/** Do not start the interface immediately after initialization.
	 * This requires that either the device driver or some other entity
	 * will need to manually take the interface up when needed.
	 * For example for Ethernet this will happen when the driver calls
	 * the net_eth_carrier_on() function.
	 */
	NET_IF_NO_AUTO_START,

	/** Power management specific: interface is being suspended */
	NET_IF_SUSPENDED,

	/** Flag defines if received multicasts of other interface are
	 * forwarded on this interface. This activates multicast
	 * routing / forwarding for this interface.
	 */
	NET_IF_FORWARD_MULTICASTS,

	/** Interface supports IPv4 */
	NET_IF_IPV4,

	/** Interface supports IPv6 */
	NET_IF_IPV6,

/** @cond INTERNAL_HIDDEN */
	/* Total number of flags - must be at the end of the enum */
	NET_IF_NUM_FLAGS
/** @endcond */
};

#if defined(CONFIG_NET_OFFLOAD)
struct net_offload;
#endif /* CONFIG_NET_OFFLOAD */

/** @cond INTERNAL_HIDDEN */
#if defined(CONFIG_NET_NATIVE_IPV6)
#define NET_IF_MAX_IPV6_ADDR CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT
#define NET_IF_MAX_IPV6_MADDR CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT
#define NET_IF_MAX_IPV6_PREFIX CONFIG_NET_IF_IPV6_PREFIX_COUNT
#else
#define NET_IF_MAX_IPV6_ADDR 0
#define NET_IF_MAX_IPV6_MADDR 0
#define NET_IF_MAX_IPV6_PREFIX 0
#endif
/* @endcond */

struct net_if_ipv6 {
	/** Unicast IP addresses */
	struct net_if_addr unicast[NET_IF_MAX_IPV6_ADDR];

	/** Multicast IP addresses */
	struct net_if_mcast_addr mcast[NET_IF_MAX_IPV6_MADDR];

	/** Prefixes */
	struct net_if_ipv6_prefix prefix[NET_IF_MAX_IPV6_PREFIX];

	/** Default reachable time (RFC 4861, page 52) */
	uint32_t base_reachable_time;

	/** Reachable time (RFC 4861, page 20) */
	uint32_t reachable_time;

	/** Retransmit timer (RFC 4861, page 52) */
	uint32_t retrans_timer;
#if defined(CONFIG_NET_IPV6_ND) && defined(CONFIG_NET_NATIVE_IPV6)
	/** Router solicitation timer node */
	sys_snode_t rs_node;

	/* RS start time */
	uint32_t rs_start;

	/** RS count */
	uint8_t rs_count;
#endif

	/** IPv6 hop limit */
	uint8_t hop_limit;
};

/** @cond INTERNAL_HIDDEN */
#if defined(CONFIG_NET_NATIVE_IPV4)
#define NET_IF_MAX_IPV4_ADDR CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT
#define NET_IF_MAX_IPV4_MADDR CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT
#else
#define NET_IF_MAX_IPV4_ADDR 0
#define NET_IF_MAX_IPV4_MADDR 0
#endif
/** @endcond */

struct net_if_ipv4 {
	/** Unicast IP addresses */
	struct net_if_addr unicast[NET_IF_MAX_IPV4_ADDR];

	/** Multicast IP addresses */
	struct net_if_mcast_addr mcast[NET_IF_MAX_IPV4_MADDR];

	/** Gateway */
	struct in_addr gw;

	/** Netmask */
	struct in_addr netmask;

	/** IPv4 time-to-live */
	uint8_t ttl;
};

#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4)
struct net_if_dhcpv4 {
	/** Used for timer lists */
	sys_snode_t node;

	/** Timer start */
	int64_t timer_start;

	/** Time for INIT, DISCOVER, REQUESTING, RENEWAL */
	uint32_t request_time;

	uint32_t xid;

	/** IP address Lease time */
	uint32_t lease_time;

	/** IP address Renewal time */
	uint32_t renewal_time;

	/** IP address Rebinding time */
	uint32_t rebinding_time;

	/** Server ID */
	struct in_addr server_id;

	/** Requested IP addr */
	struct in_addr requested_ip;

	/**
	 *  DHCPv4 client state in the process of network
	 *  address allocation.
	 */
	enum net_dhcpv4_state state;

	/** Number of attempts made for REQUEST and RENEWAL messages */
	uint8_t attempts;
};
#endif /* CONFIG_NET_DHCPV4 */

#if defined(CONFIG_NET_IPV4_AUTO) && defined(CONFIG_NET_NATIVE_IPV4)
struct net_if_ipv4_autoconf {
	/** Used for timer lists */
	sys_snode_t node;

	/** Backpointer to correct network interface */
	struct net_if *iface;

	/** Timer start */
	int64_t timer_start;

	/** Time for INIT, DISCOVER, REQUESTING, RENEWAL */
	uint32_t timer_timeout;

	/** Current IP addr */
	struct in_addr current_ip;

	/** Requested IP addr */
	struct in_addr requested_ip;

	/** IPV4 Autoconf state in the process of network address allocation.
	 */
	enum net_ipv4_autoconf_state state;

	/** Number of sent probe requests */
	uint8_t probe_cnt;

	/** Number of sent announcements */
	uint8_t announce_cnt;

	/** Incoming conflict count */
	uint8_t conflict_cnt;
};
#endif /* CONFIG_NET_IPV4_AUTO */

/** @cond INTERNAL_HIDDEN */
/* We always need to have at least one IP config */
#define NET_IF_MAX_CONFIGS 1
/** @endcond */

/**
 * @brief Network interface IP address configuration.
 */
struct net_if_ip {
#if defined(CONFIG_NET_NATIVE_IPV6)
	struct net_if_ipv6 *ipv6;
#endif /* CONFIG_NET_IPV6 */

#if defined(CONFIG_NET_NATIVE_IPV4)
	struct net_if_ipv4 *ipv4;
#endif /* CONFIG_NET_IPV4 */
};

/**
 * @brief IP and other configuration related data for network interface.
 */
struct net_if_config {
	/** IP address configuration setting */
	struct net_if_ip ip;

#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4)
	struct net_if_dhcpv4 dhcpv4;
#endif /* CONFIG_NET_DHCPV4 */

#if defined(CONFIG_NET_IPV4_AUTO) && defined(CONFIG_NET_NATIVE_IPV4)
	struct net_if_ipv4_autoconf ipv4auto;
#endif /* CONFIG_NET_IPV4_AUTO */

#if defined(CONFIG_NET_L2_VIRTUAL)
	/**
	 * This list keeps track of the virtual network interfaces
	 * that are attached to this network interface.
	 */
	sys_slist_t virtual_interfaces;
#endif /* CONFIG_NET_L2_VIRTUAL */
};

/**
 * @brief Network traffic class.
 *
 * Traffic classes are used when sending or receiving data that is classified
 * with different priorities. So some traffic can be marked as high priority
 * and it will be sent or received first. Each network packet that is
 * transmitted or received goes through a fifo to a thread that will transmit
 * it.
 */
struct net_traffic_class {
	/** Fifo for handling this Tx or Rx packet */
	struct k_fifo fifo;

	/** Traffic class handler thread */
	struct k_thread handler;

	/** Stack for this handler */
	k_thread_stack_t *stack;
};

/**
 * @brief Network Interface Device structure
 *
 * Used to handle a network interface on top of a device driver instance.
 * There can be many net_if_dev instance against the same device.
 *
 * Such interface is mainly to be used by the link layer, but is also tight
 * to a network context: it then makes the relation with a network context
 * and the network device.
 *
 * Because of the strong relationship between a device driver and such
 * network interface, each net_if_dev should be instantiated by
 */
struct net_if_dev {
	/** The actually device driver instance the net_if is related to */
	const struct device *dev;

	/** Interface's L2 layer */
	const struct net_l2 * const l2;

	/** Interface's private L2 data pointer */
	void *l2_data;

	/* For internal use */
	ATOMIC_DEFINE(flags, NET_IF_NUM_FLAGS);

	/** The hardware link address */
	struct net_linkaddr link_addr;

#if defined(CONFIG_NET_OFFLOAD)
	/** TCP/IP Offload functions.
	 * If non-NULL, then the TCP/IP stack is located
	 * in the communication chip that is accessed via this
	 * network interface.
	 */
	struct net_offload *offload;
#endif /* CONFIG_NET_OFFLOAD */

	/** The hardware MTU */
	uint16_t mtu;

#if defined(CONFIG_NET_SOCKETS_OFFLOAD)
	/** Indicate whether interface is offloaded at socket level. */
	bool offloaded;
#endif /* CONFIG_NET_SOCKETS_OFFLOAD */
};

/**
 * @brief Network Interface structure
 *
 * Used to handle a network interface on top of a net_if_dev instance.
 * There can be many net_if instance against the same net_if_dev instance.
 *
 */
struct net_if {
	/** The net_if_dev instance the net_if is related to */
	struct net_if_dev *if_dev;

#if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
	/** Network statistics related to this network interface */
	struct net_stats stats;
#endif /* CONFIG_NET_STATISTICS_PER_INTERFACE */

	/** Network interface instance configuration */
	struct net_if_config config;

#if defined(CONFIG_NET_POWER_MANAGEMENT)
	/** Keep track of packets pending in traffic queues. This is
	 * needed to avoid putting network device driver to sleep if
	 * there are packets waiting to be sent.
	 */
	int tx_pending;
#endif
};

/**
 * @brief Set a value in network interface flags
 *
 * @param iface Pointer to network interface
 * @param value Flag value
 */
static inline void net_if_flag_set(struct net_if *iface,
				   enum net_if_flag value)
{
	NET_ASSERT(iface);

	atomic_set_bit(iface->if_dev->flags, value);
}

/**
 * @brief Test and set a value in network interface flags
 *
 * @param iface Pointer to network interface
 * @param value Flag value
 *
 * @return true if the bit was set, false if it wasn't.
 */
static inline bool net_if_flag_test_and_set(struct net_if *iface,
					    enum net_if_flag value)
{
	NET_ASSERT(iface);

	return atomic_test_and_set_bit(iface->if_dev->flags, value);
}

/**
 * @brief Clear a value in network interface flags
 *
 * @param iface Pointer to network interface
 * @param value Flag value
 */
static inline void net_if_flag_clear(struct net_if *iface,
				     enum net_if_flag value)
{
	NET_ASSERT(iface);

	atomic_clear_bit(iface->if_dev->flags, value);
}

/**
 * @brief Check if a value in network interface flags is set
 *
 * @param iface Pointer to network interface
 * @param value Flag value
 *
 * @return True if the value is set, false otherwise
 */
static inline bool net_if_flag_is_set(struct net_if *iface,
				      enum net_if_flag value)
{
	if (iface == NULL) {
		return false;
	}

	return atomic_test_bit(iface->if_dev->flags, value);
}

/**
 * @brief Send a packet through a net iface
 *
 * @param iface Pointer to a network interface structure
 * @param pkt Pointer to a net packet to send
 *
 * return verdict about the packet
 */
enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt);

/**
 * @brief Get a pointer to the interface L2
 *
 * @param iface a valid pointer to a network interface structure
 *
 * @return a pointer to the iface L2
 */
static inline const struct net_l2 * const net_if_l2(struct net_if *iface)
{
	if (!iface || !iface->if_dev) {
		return NULL;
	}

	return iface->if_dev->l2;
}

/**
 * @brief Input a packet through a net iface
 *
 * @param iface Pointer to a network interface structure
 * @param pkt Pointer to a net packet to input
 *
 * @return verdict about the packet
 */
enum net_verdict net_if_recv_data(struct net_if *iface, struct net_pkt *pkt);

/**
 * @brief Get a pointer to the interface L2 private data
 *
 * @param iface a valid pointer to a network interface structure
 *
 * @return a pointer to the iface L2 data
 */
static inline void *net_if_l2_data(struct net_if *iface)
{
	return iface->if_dev->l2_data;
}

/**
 * @brief Get an network interface's device
 *
 * @param iface Pointer to a network interface structure
 *
 * @return a pointer to the device driver instance
 */
static inline const struct device *net_if_get_device(struct net_if *iface)
{
	return iface->if_dev->dev;
}

/**
 * @brief Queue a packet to the net interface TX queue
 *
 * @param iface Pointer to a network interface structure
 * @param pkt Pointer to a net packet to queue
 */
void net_if_queue_tx(struct net_if *iface, struct net_pkt *pkt);

/**
 * @brief Return the IP offload status
 *
 * @param iface Network interface
 *
 * @return True if IP offlining is active, false otherwise.
 */
static inline bool net_if_is_ip_offloaded(struct net_if *iface)
{
#if defined(CONFIG_NET_OFFLOAD)
	return (iface->if_dev->offload != NULL);
#else
	ARG_UNUSED(iface);

	return false;
#endif
}

/**
 * @brief Return the IP offload plugin
 *
 * @param iface Network interface
 *
 * @return NULL if there is no offload plugin defined, valid pointer otherwise
 */
static inline struct net_offload *net_if_offload(struct net_if *iface)
{
#if defined(CONFIG_NET_OFFLOAD)
	return iface->if_dev->offload;
#else
	ARG_UNUSED(iface);

	return NULL;
#endif
}

/**
 * @brief Return the socket offload status
 *
 * @param iface Network interface
 *
 * @return True if socket offloading is active, false otherwise.
 */
static inline bool net_if_is_socket_offloaded(struct net_if *iface)
{
#if defined(CONFIG_NET_SOCKETS_OFFLOAD)
	return iface->if_dev->offloaded;
#else
	ARG_UNUSED(iface);

	return false;
#endif
}

/**
 * @brief Get an network interface's link address
 *
 * @param iface Pointer to a network interface structure
 *
 * @return a pointer to the network link address
 */
static inline struct net_linkaddr *net_if_get_link_addr(struct net_if *iface)
{
	return &iface->if_dev->link_addr;
}

/**
 * @brief Return network configuration for this network interface
 *
 * @param iface Pointer to a network interface structure
 *
 * @return Pointer to configuration
 */
static inline struct net_if_config *net_if_get_config(struct net_if *iface)
{
	return &iface->config;
}

/**
 * @brief Start duplicate address detection procedure.
 *
 * @param iface Pointer to a network interface structure
 */
#if defined(CONFIG_NET_IPV6_DAD) && defined(CONFIG_NET_NATIVE_IPV6)
void net_if_start_dad(struct net_if *iface);
#else
static inline void net_if_start_dad(struct net_if *iface)
{
	ARG_UNUSED(iface);
}
#endif

/**
 * @brief Start neighbor discovery and send router solicitation message.
 *
 * @param iface Pointer to a network interface structure
 */
void net_if_start_rs(struct net_if *iface);


/**
 * @brief Stop neighbor discovery.
 *
 * @param iface Pointer to a network interface structure
 */
#if defined(CONFIG_NET_IPV6_ND) && defined(CONFIG_NET_NATIVE_IPV6)
void net_if_stop_rs(struct net_if *iface);
#else
static inline void net_if_stop_rs(struct net_if *iface)
{
	ARG_UNUSED(iface);
}
#endif /* CONFIG_NET_IPV6_ND */

/** @cond INTERNAL_HIDDEN */

static inline int net_if_set_link_addr_unlocked(struct net_if *iface,
						uint8_t *addr, uint8_t len,
						enum net_link_type type)
{
	if (net_if_flag_is_set(iface, NET_IF_UP)) {
		return -EPERM;
	}

	net_if_get_link_addr(iface)->addr = addr;
	net_if_get_link_addr(iface)->len = len;
	net_if_get_link_addr(iface)->type = type;

	net_hostname_set_postfix(addr, len);

	return 0;
}

int net_if_set_link_addr_locked(struct net_if *iface,
				uint8_t *addr, uint8_t len,
				enum net_link_type type);
/** @endcond */

/**
 * @brief Set a network interface's link address
 *
 * @param iface Pointer to a network interface structure
 * @param addr A pointer to a uint8_t buffer representing the address.
 *             The buffer must remain valid throughout interface lifetime.
 * @param len length of the address buffer
 * @param type network bearer type of this link address
 *
 * @return 0 on success
 */
static inline int net_if_set_link_addr(struct net_if *iface,
				       uint8_t *addr, uint8_t len,
				       enum net_link_type type)
{
#if defined(CONFIG_NET_RAW_MODE)
	return net_if_set_link_addr_unlocked(iface, addr, len, type);
#else
	return net_if_set_link_addr_locked(iface, addr, len, type);
#endif
}

/**
 * @brief Get an network interface's MTU
 *
 * @param iface Pointer to a network interface structure
 *
 * @return the MTU
 */
static inline uint16_t net_if_get_mtu(struct net_if *iface)
{
	if (iface == NULL) {
		return 0U;
	}

	return iface->if_dev->mtu;
}

/**
 * @brief Set an network interface's MTU
 *
 * @param iface Pointer to a network interface structure
 * @param mtu New MTU, note that we store only 16 bit mtu value.
 */
static inline void net_if_set_mtu(struct net_if *iface,
				  uint16_t mtu)
{
	if (iface == NULL) {
		return;
	}

	iface->if_dev->mtu = mtu;
}

/**
 * @brief Set the infinite status of the network interface address
 *
 * @param ifaddr IP address for network interface
 * @param is_infinite Infinite status
 */
static inline void net_if_addr_set_lf(struct net_if_addr *ifaddr,
				      bool is_infinite)
{
	ifaddr->is_infinite = is_infinite;
}

/**
 * @brief Get an interface according to link layer address.
 *
 * @param ll_addr Link layer address.
 *
 * @return Network interface or NULL if not found.
 */
struct net_if *net_if_get_by_link_addr(struct net_linkaddr *ll_addr);

/**
 * @brief Find an interface from it's related device
 *
 * @param dev A valid struct device pointer to relate with an interface
 *
 * @return a valid struct net_if pointer on success, NULL otherwise
 */
struct net_if *net_if_lookup_by_dev(const struct device *dev);

/**
 * @brief Get network interface IP config
 *
 * @param iface Interface to use.
 *
 * @return NULL if not found or pointer to correct config settings.
 */
static inline struct net_if_config *net_if_config_get(struct net_if *iface)
{
	return &iface->config;
}

/**
 * @brief Remove a router from the system
 *
 * @param router Pointer to existing router
 */
void net_if_router_rm(struct net_if_router *router);

/**
 * @brief Get the default network interface.
 *
 * @return Default interface or NULL if no interfaces are configured.
 */
struct net_if *net_if_get_default(void);

/**
 * @brief Get the first network interface according to its type.
 *
 * @param l2 Layer 2 type of the network interface.
 *
 * @return First network interface of a given type or NULL if no such
 * interfaces was found.
 */
struct net_if *net_if_get_first_by_type(const struct net_l2 *l2);

#if defined(CONFIG_NET_L2_IEEE802154)
/**
 * @brief Get the first IEEE 802.15.4 network interface.
 *
 * @return First IEEE 802.15.4 network interface or NULL if no such
 * interfaces was found.
 */
static inline struct net_if *net_if_get_ieee802154(void)
{
	return net_if_get_first_by_type(&NET_L2_GET_NAME(IEEE802154));
}
#endif /* CONFIG_NET_L2_IEEE802154 */

/**
 * @brief Allocate network interface IPv6 config.
 *
 * @details This function will allocate new IPv6 config.
 *
 * @param iface Interface to use.
 * @param ipv6 Pointer to allocated IPv6 struct is returned to caller.
 *
 * @return 0 if ok, <0 if error
 */
int net_if_config_ipv6_get(struct net_if *iface,
			   struct net_if_ipv6 **ipv6);

/**
 * @brief Release network interface IPv6 config.
 *
 * @param iface Interface to use.
 *
 * @return 0 if ok, <0 if error
 */
int net_if_config_ipv6_put(struct net_if *iface);

/**
 * @brief Check if this IPv6 address belongs to one of the interfaces.
 *
 * @param addr IPv6 address
 * @param iface Pointer to interface is returned
 *
 * @return Pointer to interface address, NULL if not found.
 */
struct net_if_addr *net_if_ipv6_addr_lookup(const struct in6_addr *addr,
					    struct net_if **iface);

/**
 * @brief Check if this IPv6 address belongs to this specific interfaces.
 *
 * @param iface Network interface
 * @param addr IPv6 address
 *
 * @return Pointer to interface address, NULL if not found.
 */
struct net_if_addr *net_if_ipv6_addr_lookup_by_iface(struct net_if *iface,
						     struct in6_addr *addr);

/**
 * @brief Check if this IPv6 address belongs to one of the interface indices.
 *
 * @param addr IPv6 address
 *
 * @return >0 if address was found in given network interface index,
 * all other values mean address was not found
 */
__syscall int net_if_ipv6_addr_lookup_by_index(const struct in6_addr *addr);

/**
 * @brief Add a IPv6 address to an interface
 *
 * @param iface Network interface
 * @param addr IPv6 address
 * @param addr_type IPv6 address type
 * @param vlifetime Validity time for this address
 *
 * @return Pointer to interface address, NULL if cannot be added
 */
struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
					 struct in6_addr *addr,
					 enum net_addr_type addr_type,
					 uint32_t vlifetime);

/**
 * @brief Add a IPv6 address to an interface by index
 *
 * @param index Network interface index
 * @param addr IPv6 address
 * @param addr_type IPv6 address type
 * @param vlifetime Validity time for this address
 *
 * @return True if ok, false if address could not be added
 */
__syscall bool net_if_ipv6_addr_add_by_index(int index,
					     struct in6_addr *addr,
					     enum net_addr_type addr_type,
					     uint32_t vlifetime);

/**
 * @brief Update validity lifetime time of an IPv6 address.
 *
 * @param ifaddr Network IPv6 address
 * @param vlifetime Validity time for this address
 */
void net_if_ipv6_addr_update_lifetime(struct net_if_addr *ifaddr,
				      uint32_t vlifetime);

/**
 * @brief Remove an IPv6 address from an interface
 *
 * @param iface Network interface
 * @param addr IPv6 address
 *
 * @return True if successfully removed, false otherwise
 */
bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr);

/**
 * @brief Remove an IPv6 address from an interface by index
 *
 * @param index Network interface index
 * @param addr IPv6 address
 *
 * @return True if successfully removed, false otherwise
 */
__syscall bool net_if_ipv6_addr_rm_by_index(int index,
					    const struct in6_addr *addr);

/**
 * @brief Add a IPv6 multicast address to an interface
 *
 * @param iface Network interface
 * @param addr IPv6 multicast address
 *
 * @return Pointer to interface multicast address, NULL if cannot be added
 */
struct net_if_mcast_addr *net_if_ipv6_maddr_add(struct net_if *iface,
						const struct in6_addr *addr);

/**
 * @brief Remove an IPv6 multicast address from an interface
 *
 * @param iface Network interface
 * @param addr IPv6 multicast address
 *
 * @return True if successfully removed, false otherwise
 */
bool net_if_ipv6_maddr_rm(struct net_if *iface, const struct in6_addr *addr);

/**
 * @brief Check if this IPv6 multicast address belongs to a specific interface
 * or one of the interfaces.
 *
 * @param addr IPv6 address
 * @param iface If *iface is null, then pointer to interface is returned,
 * otherwise the *iface value needs to be matched.
 *
 * @return Pointer to interface multicast address, NULL if not found.
 */
struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(const struct in6_addr *addr,
						   struct net_if **iface);

/**
 * @typedef net_if_mcast_callback_t

 * @brief Define callback that is called whenever IPv6 multicast address group
 * is joined or left.

 * @param iface A pointer to a struct net_if to which the multicast address is
 *        attached.
 * @param addr IP multicast address.
 * @param is_joined True if the address is joined, false if left.
 */
typedef void (*net_if_mcast_callback_t)(struct net_if *iface,
					const struct net_addr *addr,
					bool is_joined);

/**
 * @brief Multicast monitor handler struct.
 *
 * Stores the multicast callback information. Caller must make sure that
 * the variable pointed by this is valid during the lifetime of
 * registration. Typically this means that the variable cannot be
 * allocated from stack.
 */
struct net_if_mcast_monitor {
	/** Node information for the slist. */
	sys_snode_t node;

	/** Network interface */
	struct net_if *iface;

	/** Multicast callback */
	net_if_mcast_callback_t cb;
};

/**
 * @brief Register a multicast monitor
 *
 * @param mon Monitor handle. This is a pointer to a monitor storage structure
 * which should be allocated by caller, but does not need to be initialized.
 * @param iface Network interface
 * @param cb Monitor callback
 */
void net_if_mcast_mon_register(struct net_if_mcast_monitor *mon,
			       struct net_if *iface,
			       net_if_mcast_callback_t cb);

/**
 * @brief Unregister a multicast monitor
 *
 * @param mon Monitor handle
 */
void net_if_mcast_mon_unregister(struct net_if_mcast_monitor *mon);

/**
 * @brief Call registered multicast monitors
 *
 * @param iface Network interface
 * @param addr Multicast address
 * @param is_joined Is this multicast address joined (true) or not (false)
 */
void net_if_mcast_monitor(struct net_if *iface, const struct net_addr *addr,
			  bool is_joined);

/**
 * @brief Mark a given multicast address to be joined.
 *
 * @param addr IPv6 multicast address
 */
void net_if_ipv6_maddr_join(struct net_if_mcast_addr *addr);

/**
 * @brief Check if given multicast address is joined or not.
 *
 * @param addr IPv6 multicast address
 *
 * @return True if address is joined, False otherwise.
 */
static inline bool net_if_ipv6_maddr_is_joined(struct net_if_mcast_addr *addr)
{
	NET_ASSERT(addr);

	return addr->is_joined;
}

/**
 * @brief Mark a given multicast address to be left.
 *
 * @param addr IPv6 multicast address
 */
void net_if_ipv6_maddr_leave(struct net_if_mcast_addr *addr);

/**
 * @brief Return prefix that corresponds to this IPv6 address.
 *
 * @param iface Network interface
 * @param addr IPv6 address
 *
 * @return Pointer to prefix, NULL if not found.
 */
struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface,
						  struct in6_addr *addr);

/**
 * @brief Check if this IPv6 prefix belongs to this interface
 *
 * @param iface Network interface
 * @param addr IPv6 address
 * @param len Prefix length
 *
 * @return Pointer to prefix, NULL if not found.
 */
struct net_if_ipv6_prefix *net_if_ipv6_prefix_lookup(struct net_if *iface,
						     struct in6_addr *addr,
						     uint8_t len);

/**
 * @brief Add a IPv6 prefix to an network interface.
 *
 * @param iface Network interface
 * @param prefix IPv6 address
 * @param len Prefix length
 * @param lifetime Prefix lifetime in seconds
 *
 * @return Pointer to prefix, NULL if the prefix was not added.
 */
struct net_if_ipv6_prefix *net_if_ipv6_prefix_add(struct net_if *iface,
						  struct in6_addr *prefix,
						  uint8_t len,
						  uint32_t lifetime);

/**
 * @brief Remove an IPv6 prefix from an interface
 *
 * @param iface Network interface
 * @param addr IPv6 prefix address
 * @param len Prefix length
 *
 * @return True if successfully removed, false otherwise
 */
bool net_if_ipv6_prefix_rm(struct net_if *iface, struct in6_addr *addr,
			   uint8_t len);

/**
 * @brief Set the infinite status of the prefix
 *
 * @param prefix IPv6 address
 * @param is_infinite Infinite status
 */
static inline void net_if_ipv6_prefix_set_lf(struct net_if_ipv6_prefix *prefix,
					     bool is_infinite)
{
	prefix->is_infinite = is_infinite;
}

/**
 * @brief Set the prefix lifetime timer.
 *
 * @param prefix IPv6 address
 * @param lifetime Prefix lifetime in seconds
 */
void net_if_ipv6_prefix_set_timer(struct net_if_ipv6_prefix *prefix,
				  uint32_t lifetime);

/**
 * @brief Unset the prefix lifetime timer.
 *
 * @param prefix IPv6 address
 */
void net_if_ipv6_prefix_unset_timer(struct net_if_ipv6_prefix *prefix);

/**
 * @brief Check if this IPv6 address is part of the subnet of our
 * network interface.
 *
 * @param iface Network interface. This is returned to the caller.
 * The iface can be NULL in which case we check all the interfaces.
 * @param addr IPv6 address
 *
 * @return True if address is part of our subnet, false otherwise
 */
bool net_if_ipv6_addr_onlink(struct net_if **iface, struct in6_addr *addr);

/**
 * @brief Get the IPv6 address of the given router
 * @param router a network router
 *
 * @return pointer to the IPv6 address, or NULL if none
 */
#if defined(CONFIG_NET_NATIVE_IPV6)
static inline struct in6_addr *net_if_router_ipv6(struct net_if_router *router)
{
	return &router->address.in6_addr;
}
#else
static inline struct in6_addr *net_if_router_ipv6(struct net_if_router *router)
{
	static struct in6_addr addr;

	ARG_UNUSED(router);

	return &addr;
}
#endif

/**
 * @brief Check if IPv6 address is one of the routers configured
 * in the system.
 *
 * @param iface Network interface
 * @param addr IPv6 address
 *
 * @return Pointer to router information, NULL if cannot be found
 */
struct net_if_router *net_if_ipv6_router_lookup(struct net_if *iface,
						struct in6_addr *addr);

/**
 * @brief Find default router for this IPv6 address.
 *
 * @param iface Network interface. This can be NULL in which case we
 * go through all the network interfaces to find a suitable router.
 * @param addr IPv6 address
 *
 * @return Pointer to router information, NULL if cannot be found
 */
struct net_if_router *net_if_ipv6_router_find_default(struct net_if *iface,
						      struct in6_addr *addr);

/**
 * @brief Update validity lifetime time of a router.
 *
 * @param router Network IPv6 address
 * @param lifetime Lifetime of this router.
 */
void net_if_ipv6_router_update_lifetime(struct net_if_router *router,
					uint16_t lifetime);

/**
 * @brief Add IPv6 router to the system.
 *
 * @param iface Network interface
 * @param addr IPv6 address
 * @param router_lifetime Lifetime of the router
 *
 * @return Pointer to router information, NULL if could not be added
 */
struct net_if_router *net_if_ipv6_router_add(struct net_if *iface,
					     struct in6_addr *addr,
					     uint16_t router_lifetime);

/**
 * @brief Remove IPv6 router from the system.
 *
 * @param router Router information.
 *
 * @return True if successfully removed, false otherwise
 */
bool net_if_ipv6_router_rm(struct net_if_router *router);

/**
 * @brief Get IPv6 hop limit specified for a given interface. This is the
 * default value but can be overridden by the user.
 *
 * @param iface Network interface
 *
 * @return Hop limit
 */
uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface);

/**
 * @brief Set the default IPv6 hop limit of a given interface.
 *
 * @param iface Network interface
 * @param hop_limit New hop limit
 */
void net_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit);

/**
 * @brief Set IPv6 reachable time for a given interface
 *
 * @param iface Network interface
 * @param reachable_time New reachable time
 */
static inline void net_if_ipv6_set_base_reachable_time(struct net_if *iface,
						       uint32_t reachable_time)
{
#if defined(CONFIG_NET_NATIVE_IPV6)
	if (!iface->config.ip.ipv6) {
		return;
	}

	iface->config.ip.ipv6->base_reachable_time = reachable_time;
#endif
}

/**
 * @brief Get IPv6 reachable timeout specified for a given interface
 *
 * @param iface Network interface
 *
 * @return Reachable timeout
 */
static inline uint32_t net_if_ipv6_get_reachable_time(struct net_if *iface)
{
#if defined(CONFIG_NET_NATIVE_IPV6)
	if (!iface->config.ip.ipv6) {
		return 0;
	}

	return iface->config.ip.ipv6->reachable_time;
#else
	return 0;
#endif
}

/**
 * @brief Calculate next reachable time value for IPv6 reachable time
 *
 * @param ipv6 IPv6 address configuration
 *
 * @return Reachable time
 */
uint32_t net_if_ipv6_calc_reachable_time(struct net_if_ipv6 *ipv6);

/**
 * @brief Set IPv6 reachable time for a given interface. This requires
 * that base reachable time is set for the interface.
 *
 * @param ipv6 IPv6 address configuration
 */
static inline void net_if_ipv6_set_reachable_time(struct net_if_ipv6 *ipv6)
{
#if defined(CONFIG_NET_NATIVE_IPV6)
	ipv6->reachable_time = net_if_ipv6_calc_reachable_time(ipv6);
#endif
}

/**
 * @brief Set IPv6 retransmit timer for a given interface
 *
 * @param iface Network interface
 * @param retrans_timer New retransmit timer
 */
static inline void net_if_ipv6_set_retrans_timer(struct net_if *iface,
						 uint32_t retrans_timer)
{
#if defined(CONFIG_NET_NATIVE_IPV6)
	if (!iface->config.ip.ipv6) {
		return;
	}

	iface->config.ip.ipv6->retrans_timer = retrans_timer;
#endif
}

/**
 * @brief Get IPv6 retransmit timer specified for a given interface
 *
 * @param iface Network interface
 *
 * @return Retransmit timer
 */
static inline uint32_t net_if_ipv6_get_retrans_timer(struct net_if *iface)
{
#if defined(CONFIG_NET_NATIVE_IPV6)
	if (!iface->config.ip.ipv6) {
		return 0;
	}

	return iface->config.ip.ipv6->retrans_timer;
#else
	return 0;
#endif
}

/**
 * @brief Get a IPv6 source address that should be used when sending
 * network data to destination.
 *
 * @param iface Interface that was used when packet was received.
 * If the interface is not known, then NULL can be given.
 * @param dst IPv6 destination address
 *
 * @return Pointer to IPv6 address to use, NULL if no IPv6 address
 * could be found.
 */
#if defined(CONFIG_NET_NATIVE_IPV6)
const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *iface,
						   const struct in6_addr *dst);
#else
static inline const struct in6_addr *net_if_ipv6_select_src_addr(
	struct net_if *iface, const struct in6_addr *dst)
{
	ARG_UNUSED(iface);
	ARG_UNUSED(dst);

	return NULL;
}
#endif

/**
 * @brief Get a network interface that should be used when sending
 * IPv6 network data to destination.
 *
 * @param dst IPv6 destination address
 *
 * @return Pointer to network interface to use, NULL if no suitable interface
 * could be found.
 */
#if defined(CONFIG_NET_NATIVE_IPV6)
struct net_if *net_if_ipv6_select_src_iface(const struct in6_addr *dst);
#else
static inline struct net_if *net_if_ipv6_select_src_iface(
	const struct in6_addr *dst)
{
	ARG_UNUSED(dst);

	return NULL;
}
#endif

/**
 * @brief Get a IPv6 link local address in a given state.
 *
 * @param iface Interface to use. Must be a valid pointer to an interface.
 * @param addr_state IPv6 address state (preferred, tentative, deprecated)
 *
 * @return Pointer to link local IPv6 address, NULL if no proper IPv6 address
 * could be found.
 */
struct in6_addr *net_if_ipv6_get_ll(struct net_if *iface,
				    enum net_addr_state addr_state);

/**
 * @brief Return link local IPv6 address from the first interface that has
 * a link local address matching give state.
 *
 * @param state IPv6 address state (ANY, TENTATIVE, PREFERRED, DEPRECATED)
 * @param iface Pointer to interface is returned
 *
 * @return Pointer to IPv6 address, NULL if not found.
 */
struct in6_addr *net_if_ipv6_get_ll_addr(enum net_addr_state state,
					 struct net_if **iface);

/**
 * @brief Stop IPv6 Duplicate Address Detection (DAD) procedure if
 * we find out that our IPv6 address is already in use.
 *
 * @param iface Interface where the DAD was running.
 * @param addr IPv6 address that failed DAD
 */
void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr);

/**
 * @brief Return global IPv6 address from the first interface that has
 * a global IPv6 address matching the given state.
 *
 * @param state IPv6 address state (ANY, TENTATIVE, PREFERRED, DEPRECATED)
 * @param iface Caller can give an interface to check. If iface is set to NULL,
 * then all the interfaces are checked. Pointer to interface where the IPv6
 * address is defined is returned to the caller.
 *
 * @return Pointer to IPv6 address, NULL if not found.
 */
struct in6_addr *net_if_ipv6_get_global_addr(enum net_addr_state state,
					     struct net_if **iface);

/**
 * @brief Allocate network interface IPv4 config.
 *
 * @details This function will allocate new IPv4 config.
 *
 * @param iface Interface to use.
 * @param ipv4 Pointer to allocated IPv4 struct is returned to caller.
 *
 * @return 0 if ok, <0 if error
 */
int net_if_config_ipv4_get(struct net_if *iface,
			   struct net_if_ipv4 **ipv4);

/**
 * @brief Release network interface IPv4 config.
 *
 * @param iface Interface to use.
 *
 * @return 0 if ok, <0 if error
 */
int net_if_config_ipv4_put(struct net_if *iface);

/**
 * @brief Get IPv4 time-to-live value specified for a given interface
 *
 * @param iface Network interface
 *
 * @return Time-to-live
 */
uint8_t net_if_ipv4_get_ttl(struct net_if *iface);

/**
 * @brief Set IPv4 time-to-live value specified to a given interface
 *
 * @param iface Network interface
 * @param ttl Time-to-live value
 */
void net_if_ipv4_set_ttl(struct net_if *iface, uint8_t ttl);

/**
 * @brief Check if this IPv4 address belongs to one of the interfaces.
 *
 * @param addr IPv4 address
 * @param iface Interface is returned
 *
 * @return Pointer to interface address, NULL if not found.
 */
struct net_if_addr *net_if_ipv4_addr_lookup(const struct in_addr *addr,
					    struct net_if **iface);

/**
 * @brief Add a IPv4 address to an interface
 *
 * @param iface Network interface
 * @param addr IPv4 address
 * @param addr_type IPv4 address type
 * @param vlifetime Validity time for this address
 *
 * @return Pointer to interface address, NULL if cannot be added
 */
struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
					 struct in_addr *addr,
					 enum net_addr_type addr_type,
					 uint32_t vlifetime);

/**
 * @brief Remove a IPv4 address from an interface
 *
 * @param iface Network interface
 * @param addr IPv4 address
 *
 * @return True if successfully removed, false otherwise
 */
bool net_if_ipv4_addr_rm(struct net_if *iface, const struct in_addr *addr);

/**
 * @brief Check if this IPv4 address belongs to one of the interface indices.
 *
 * @param addr IPv4 address
 *
 * @return >0 if address was found in given network interface index,
 * all other values mean address was not found
 */
__syscall int net_if_ipv4_addr_lookup_by_index(const struct in_addr *addr);

/**
 * @brief Add a IPv4 address to an interface by network interface index
 *
 * @param index Network interface index
 * @param addr IPv4 address
 * @param addr_type IPv4 address type
 * @param vlifetime Validity time for this address
 *
 * @return True if ok, false if the address could not be added
 */
__syscall bool net_if_ipv4_addr_add_by_index(int index,
					     struct in_addr *addr,
					     enum net_addr_type addr_type,
					     uint32_t vlifetime);

/**
 * @brief Remove a IPv4 address from an interface by interface index
 *
 * @param index Network interface index
 * @param addr IPv4 address
 *
 * @return True if successfully removed, false otherwise
 */
__syscall bool net_if_ipv4_addr_rm_by_index(int index,
					    const struct in_addr *addr);

/**
 * @brief Add a IPv4 multicast address to an interface
 *
 * @param iface Network interface
 * @param addr IPv4 multicast address
 *
 * @return Pointer to interface multicast address, NULL if cannot be added
 */
struct net_if_mcast_addr *net_if_ipv4_maddr_add(struct net_if *iface,
						const struct in_addr *addr);

/**
 * @brief Remove an IPv4 multicast address from an interface
 *
 * @param iface Network interface
 * @param addr IPv4 multicast address
 *
 * @return True if successfully removed, false otherwise
 */
bool net_if_ipv4_maddr_rm(struct net_if *iface, const struct in_addr *addr);

/**
 * @brief Check if this IPv4 multicast address belongs to a specific interface
 * or one of the interfaces.
 *
 * @param addr IPv4 address
 * @param iface If *iface is null, then pointer to interface is returned,
 * otherwise the *iface value needs to be matched.
 *
 * @return Pointer to interface multicast address, NULL if not found.
 */
struct net_if_mcast_addr *net_if_ipv4_maddr_lookup(const struct in_addr *addr,
						   struct net_if **iface);

/**
 * @brief Mark a given multicast address to be joined.
 *
 * @param addr IPv4 multicast address
 */
void net_if_ipv4_maddr_join(struct net_if_mcast_addr *addr);

/**
 * @brief Check if given multicast address is joined or not.
 *
 * @param addr IPv4 multicast address
 *
 * @return True if address is joined, False otherwise.
 */
static inline bool net_if_ipv4_maddr_is_joined(struct net_if_mcast_addr *addr)
{
	NET_ASSERT(addr);

	return addr->is_joined;
}

/**
 * @brief Mark a given multicast address to be left.
 *
 * @param addr IPv4 multicast address
 */
void net_if_ipv4_maddr_leave(struct net_if_mcast_addr *addr);

/**
 * @brief Get the IPv4 address of the given router
 * @param router a network router
 *
 * @return pointer to the IPv4 address, or NULL if none
 */
#if defined(CONFIG_NET_NATIVE_IPV4)
static inline struct in_addr *net_if_router_ipv4(struct net_if_router *router)
{
	return &router->address.in_addr;
}
#else
static inline struct in_addr *net_if_router_ipv4(struct net_if_router *router)
{
	static struct in_addr addr;

	ARG_UNUSED(router);

	return &addr;
}
#endif

/**
 * @brief Check if IPv4 address is one of the routers configured
 * in the system.
 *
 * @param iface Network interface
 * @param addr IPv4 address
 *
 * @return Pointer to router information, NULL if cannot be found
 */
struct net_if_router *net_if_ipv4_router_lookup(struct net_if *iface,
						struct in_addr *addr);

/**
 * @brief Find default router for this IPv4 address.
 *
 * @param iface Network interface. This can be NULL in which case we
 * go through all the network interfaces to find a suitable router.
 * @param addr IPv4 address
 *
 * @return Pointer to router information, NULL if cannot be found
 */
struct net_if_router *net_if_ipv4_router_find_default(struct net_if *iface,
						      struct in_addr *addr);
/**
 * @brief Add IPv4 router to the system.
 *
 * @param iface Network interface
 * @param addr IPv4 address
 * @param is_default Is this router the default one
 * @param router_lifetime Lifetime of the router
 *
 * @return Pointer to router information, NULL if could not be added
 */
struct net_if_router *net_if_ipv4_router_add(struct net_if *iface,
					     struct in_addr *addr,
					     bool is_default,
					     uint16_t router_lifetime);

/**
 * @brief Remove IPv4 router from the system.
 *
 * @param router Router information.
 *
 * @return True if successfully removed, false otherwise
 */
bool net_if_ipv4_router_rm(struct net_if_router *router);

/**
 * @brief Check if the given IPv4 address belongs to local subnet.
 *
 * @param iface Interface to use. Must be a valid pointer to an interface.
 * @param addr IPv4 address
 *
 * @return True if address is part of local subnet, false otherwise.
 */
bool net_if_ipv4_addr_mask_cmp(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, this should be in network byte order
 *
 * @return True if address is a broadcast address, false otherwise.
 */
bool net_if_ipv4_is_addr_bcast(struct net_if *iface,
			       const struct in_addr *addr);

/**
 * @brief Get a network interface that should be used when sending
 * IPv4 network data to destination.
 *
 * @param dst IPv4 destination address
 *
 * @return Pointer to network interface to use, NULL if no suitable interface
 * could be found.
 */
#if defined(CONFIG_NET_NATIVE_IPV4)
struct net_if *net_if_ipv4_select_src_iface(const struct in_addr *dst);
#else
static inline struct net_if *net_if_ipv4_select_src_iface(
	const struct in_addr *dst)
{
	ARG_UNUSED(dst);

	return NULL;
}
#endif

/**
 * @brief Get a IPv4 source address that should be used when sending
 * network data to destination.
 *
 * @param iface Interface to use when sending the packet.
 * If the interface is not known, then NULL can be given.
 * @param dst IPv4 destination address
 *
 * @return Pointer to IPv4 address to use, NULL if no IPv4 address
 * could be found.
 */
#if defined(CONFIG_NET_NATIVE_IPV4)
const struct in_addr *net_if_ipv4_select_src_addr(struct net_if *iface,
						  const struct in_addr *dst);
#else
static inline const struct in_addr *net_if_ipv4_select_src_addr(
	struct net_if *iface, const struct in_addr *dst)
{
	ARG_UNUSED(iface);
	ARG_UNUSED(dst);

	return NULL;
}
#endif

/**
 * @brief Get a IPv4 link local address in a given state.
 *
 * @param iface Interface to use. Must be a valid pointer to an interface.
 * @param addr_state IPv4 address state (preferred, tentative, deprecated)
 *
 * @return Pointer to link local IPv4 address, NULL if no proper IPv4 address
 * could be found.
 */
struct in_addr *net_if_ipv4_get_ll(struct net_if *iface,
				   enum net_addr_state addr_state);

/**
 * @brief Get a IPv4 global address in a given state.
 *
 * @param iface Interface to use. Must be a valid pointer to an interface.
 * @param addr_state IPv4 address state (preferred, tentative, deprecated)
 *
 * @return Pointer to link local IPv4 address, NULL if no proper IPv4 address
 * could be found.
 */
struct in_addr *net_if_ipv4_get_global_addr(struct net_if *iface,
					    enum net_addr_state addr_state);

/**
 * @brief Set IPv4 netmask for an interface.
 *
 * @param iface Interface to use.
 * @param netmask IPv4 netmask
 */
void net_if_ipv4_set_netmask(struct net_if *iface,
			     const struct in_addr *netmask);

/**
 * @brief Set IPv4 netmask for an interface index.
 *
 * @param index Network interface index
 * @param netmask IPv4 netmask
 *
 * @return True if netmask was added, false otherwise.
 */
__syscall bool net_if_ipv4_set_netmask_by_index(int index,
						const struct in_addr *netmask);

/**
 * @brief Set IPv4 gateway for an interface.
 *
 * @param iface Interface to use.
 * @param gw IPv4 address of an gateway
 */
void net_if_ipv4_set_gw(struct net_if *iface, const struct in_addr *gw);

/**
 * @brief Set IPv4 gateway for an interface index.
 *
 * @param index Network interface index
 * @param gw IPv4 address of an gateway
 *
 * @return True if gateway was added, false otherwise.
 */
__syscall bool net_if_ipv4_set_gw_by_index(int index, const struct in_addr *gw);

/**
 * @brief Get a network interface that should be used when sending
 * IPv6 or IPv4 network data to destination.
 *
 * @param dst IPv6 or IPv4 destination address
 *
 * @return Pointer to network interface to use. Note that the function
 * will return the default network interface if the best network interface
 * is not found.
 */
struct net_if *net_if_select_src_iface(const struct sockaddr *dst);

/**
 * @typedef net_if_link_callback_t
 * @brief Define callback that is called after a network packet
 *        has been sent.
 * @param iface A pointer to a struct net_if to which the the net_pkt was sent to.
 * @param dst Link layer address of the destination where the network packet was sent.
 * @param status Send status, 0 is ok, < 0 error.
 */
typedef void (*net_if_link_callback_t)(struct net_if *iface,
				       struct net_linkaddr *dst,
				       int status);

/**
 * @brief Link callback handler struct.
 *
 * Stores the link callback information. Caller must make sure that
 * the variable pointed by this is valid during the lifetime of
 * registration. Typically this means that the variable cannot be
 * allocated from stack.
 */
struct net_if_link_cb {
	/** Node information for the slist. */
	sys_snode_t node;

	/** Link callback */
	net_if_link_callback_t cb;
};

/**
 * @brief Register a link callback.
 *
 * @param link Caller specified handler for the callback.
 * @param cb Callback to register.
 */
void net_if_register_link_cb(struct net_if_link_cb *link,
			     net_if_link_callback_t cb);

/**
 * @brief Unregister a link callback.
 *
 * @param link Caller specified handler for the callback.
 */
void net_if_unregister_link_cb(struct net_if_link_cb *link);

/**
 * @brief Call a link callback function.
 *
 * @param iface Network interface.
 * @param lladdr Destination link layer address
 * @param status 0 is ok, < 0 error
 */
void net_if_call_link_cb(struct net_if *iface, struct net_linkaddr *lladdr,
			 int status);

/**
 * @brief Check if received network packet checksum calculation can be avoided
 * or not. For example many ethernet devices support network packet offloading
 * in which case the IP stack does not need to calculate the checksum.
 *
 * @param iface Network interface
 *
 * @return True if checksum needs to be calculated, false otherwise.
 */
bool net_if_need_calc_rx_checksum(struct net_if *iface);

/**
 * @brief Check if network packet checksum calculation can be avoided or not
 * when sending the packet. For example many ethernet devices support network
 * packet offloading in which case the IP stack does not need to calculate the
 * checksum.
 *
 * @param iface Network interface
 *
 * @return True if checksum needs to be calculated, false otherwise.
 */
bool net_if_need_calc_tx_checksum(struct net_if *iface);

/**
 * @brief Get interface according to index
 *
 * @details This is a syscall only to provide access to the object for purposes
 *          of assigning permissions.
 *
 * @param index Interface index
 *
 * @return Pointer to interface or NULL if not found.
 */
__syscall struct net_if *net_if_get_by_index(int index);

/**
 * @brief Get interface index according to pointer
 *
 * @param iface Pointer to network interface
 *
 * @return Interface index
 */
int net_if_get_by_iface(struct net_if *iface);

/**
 * @typedef net_if_cb_t
 * @brief Callback used while iterating over network interfaces
 *
 * @param iface Pointer to current network interface
 * @param user_data A valid pointer to user data or NULL
 */
typedef void (*net_if_cb_t)(struct net_if *iface, void *user_data);

/**
 * @brief Go through all the network interfaces and call callback
 * for each interface.
 *
 * @param cb User-supplied callback function to call
 * @param user_data User specified data
 */
void net_if_foreach(net_if_cb_t cb, void *user_data);

/**
 * @brief Bring interface up
 *
 * @param iface Pointer to network interface
 *
 * @return 0 on success
 */
int net_if_up(struct net_if *iface);

/**
 * @brief Check if interface is up.
 *
 * @param iface Pointer to network interface
 *
 * @return True if interface is up, False if it is down.
 */
static inline bool net_if_is_up(struct net_if *iface)
{
	NET_ASSERT(iface);

	return net_if_flag_is_set(iface, NET_IF_UP);
}

/**
 * @brief Bring interface down
 *
 * @param iface Pointer to network interface
 *
 * @return 0 on success
 */
int net_if_down(struct net_if *iface);

#if defined(CONFIG_NET_PKT_TIMESTAMP) && defined(CONFIG_NET_NATIVE)
/**
 * @typedef net_if_timestamp_callback_t
 * @brief Define callback that is called after a network packet
 *        has been timestamped.
 * @param "struct net_pkt *pkt" A pointer on a struct net_pkt which has
 *        been timestamped after being sent.
 */
typedef void (*net_if_timestamp_callback_t)(struct net_pkt *pkt);

/**
 * @brief Timestamp callback handler struct.
 *
 * Stores the timestamp callback information. Caller must make sure that
 * the variable pointed by this is valid during the lifetime of
 * registration. Typically this means that the variable cannot be
 * allocated from stack.
 */
struct net_if_timestamp_cb {
	/** Node information for the slist. */
	sys_snode_t node;

	/** Packet for which the callback is needed.
	 *  A NULL value means all packets.
	 */
	struct net_pkt *pkt;

	/** Net interface for which the callback is needed.
	 *  A NULL value means all interfaces.
	 */
	struct net_if *iface;

	/** Timestamp callback */
	net_if_timestamp_callback_t cb;
};

/**
 * @brief Register a timestamp callback.
 *
 * @param handle Caller specified handler for the callback.
 * @param pkt Net packet for which the callback is registered. NULL for all
 * 	      packets.
 * @param iface Net interface for which the callback is. NULL for all
 *		interfaces.
 * @param cb Callback to register.
 */
void net_if_register_timestamp_cb(struct net_if_timestamp_cb *handle,
				  struct net_pkt *pkt,
				  struct net_if *iface,
				  net_if_timestamp_callback_t cb);

/**
 * @brief Unregister a timestamp callback.
 *
 * @param handle Caller specified handler for the callback.
 */
void net_if_unregister_timestamp_cb(struct net_if_timestamp_cb *handle);

/**
 * @brief Call a timestamp callback function.
 *
 * @param pkt Network buffer.
 */
void net_if_call_timestamp_cb(struct net_pkt *pkt);

/*
 * @brief Add timestamped TX buffer to be handled
 *
 * @param pkt Timestamped buffer
 */
void net_if_add_tx_timestamp(struct net_pkt *pkt);
#endif /* CONFIG_NET_PKT_TIMESTAMP */

/**
 * @brief Set network interface into promiscuous mode
 *
 * @details Note that not all network technologies will support this.
 *
 * @param iface Pointer to network interface
 *
 * @return 0 on success, <0 if error
 */
int net_if_set_promisc(struct net_if *iface);

/**
 * @brief Set network interface into normal mode
 *
 * @param iface Pointer to network interface
 */
void net_if_unset_promisc(struct net_if *iface);

/**
 * @brief Check if promiscuous mode is set or not.
 *
 * @param iface Pointer to network interface
 *
 * @return True if interface is in promisc mode,
 *         False if interface is not in in promiscuous mode.
 */
bool net_if_is_promisc(struct net_if *iface);

/**
 * @brief Check if there are any pending TX network data for a given network
 *        interface.
 *
 * @param iface Pointer to network interface
 *
 * @return True if there are pending TX network packets for this network
 *         interface, False otherwise.
 */
static inline bool net_if_are_pending_tx_packets(struct net_if *iface)
{
#if defined(CONFIG_NET_POWER_MANAGEMENT)
	return !!iface->tx_pending;
#else
	ARG_UNUSED(iface);

	return false;
#endif
}

#ifdef CONFIG_NET_POWER_MANAGEMENT
/**
 * @brief Suspend a network interface from a power management perspective
 *
 * @param iface Pointer to network interface
 *
 * @return 0 on success, or -EALREADY/-EBUSY as possible errors.
 */
int net_if_suspend(struct net_if *iface);

/**
 * @brief Resume a network interface from a power management perspective
 *
 * @param iface Pointer to network interface
 *
 * @return 0 on success, or -EALREADY as a possible error.
 */
int net_if_resume(struct net_if *iface);

/**
 * @brief Check if the network interface is suspended or not.
 *
 * @param iface Pointer to network interface
 *
 * @return True if interface is suspended, False otherwise.
 */
bool net_if_is_suspended(struct net_if *iface);
#endif /* CONFIG_NET_POWER_MANAGEMENT */

/** @cond INTERNAL_HIDDEN */
struct net_if_api {
	void (*init)(struct net_if *iface);
};

#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4)
#define NET_IF_DHCPV4_INIT .dhcpv4.state = NET_DHCPV4_DISABLED,
#else
#define NET_IF_DHCPV4_INIT
#endif

#define NET_IF_CONFIG_INIT				\
	.config = {					\
		.ip = {					\
		},					\
		NET_IF_DHCPV4_INIT			\
	}

#define NET_IF_GET_NAME(dev_name, sfx) __net_if_##dev_name##_##sfx
#define NET_IF_DEV_GET_NAME(dev_name, sfx) __net_if_dev_##dev_name##_##sfx

#define NET_IF_GET(dev_name, sfx)					\
	((struct net_if *)&NET_IF_GET_NAME(dev_name, sfx))

#define NET_IF_INIT(dev_name, sfx, _l2, _mtu, _num_configs)		\
	static STRUCT_SECTION_ITERABLE(net_if_dev,			\
				NET_IF_DEV_GET_NAME(dev_name, sfx)) = { \
		.dev = &(DEVICE_NAME_GET(dev_name)),			\
		.l2 = &(NET_L2_GET_NAME(_l2)),				\
		.l2_data = &(NET_L2_GET_DATA(dev_name, sfx)),		\
		.mtu = _mtu,						\
	};								\
	static Z_DECL_ALIGN(struct net_if)				\
		       NET_IF_GET_NAME(dev_name, sfx)[_num_configs]	\
		       __used __in_section(_net_if, static,             \
					   dev_name) = {                \
		[0 ... (_num_configs - 1)] = {				\
			.if_dev = &(NET_IF_DEV_GET_NAME(dev_name, sfx)), \
			NET_IF_CONFIG_INIT				\
		}							\
	}

#define NET_IF_OFFLOAD_INIT(dev_name, sfx, _mtu)			\
	static STRUCT_SECTION_ITERABLE(net_if_dev,			\
				NET_IF_DEV_GET_NAME(dev_name, sfx)) = {	\
		.dev = &(DEVICE_NAME_GET(dev_name)),			\
		.mtu = _mtu,						\
	};								\
	static Z_DECL_ALIGN(struct net_if)				\
		NET_IF_GET_NAME(dev_name, sfx)[NET_IF_MAX_CONFIGS]	\
		       __used __in_section(_net_if, static,             \
					   dev_name) = {                \
		[0 ... (NET_IF_MAX_CONFIGS - 1)] = {			\
			.if_dev = &(NET_IF_DEV_GET_NAME(dev_name, sfx)), \
			NET_IF_CONFIG_INIT				\
		}							\
	}

/** @endcond */

/* Network device initialization macros */

#define Z_NET_DEVICE_INIT(node_id, dev_name, drv_name, init_fn,		\
			pm_action_cb, data, cfg, prio, api, l2,	\
			l2_ctx_type, mtu)				\
	Z_DEVICE_STATE_DEFINE(node_id, dev_name)			\
	Z_DEVICE_DEFINE(node_id, dev_name, drv_name, init_fn,		\
			pm_action_cb, data,				\
			cfg, POST_KERNEL, prio, api,			\
			&Z_DEVICE_STATE_NAME(dev_name));		\
	NET_L2_DATA_INIT(dev_name, 0, l2_ctx_type);			\
	NET_IF_INIT(dev_name, 0, l2, mtu, NET_IF_MAX_CONFIGS)

/**
 * @def NET_DEVICE_INIT
 *
 * @brief Create a network interface and bind it to network device.
 *
 * @param dev_name Network device name.
 * @param drv_name The name this instance of the driver exposes to
 * the system.
 * @param init_fn Address to the init function of the driver.
 * @param pm_action_cb Pointer to PM action callback.
 * Can be NULL if not implemented.
 * @param data Pointer to the device's private data.
 * @param cfg The address to the structure containing the
 * configuration information for this instance of the driver.
 * @param prio The initialization level at which configuration occurs.
 * @param api Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 * @param l2 Network L2 layer for this network interface.
 * @param l2_ctx_type Type of L2 context data.
 * @param mtu Maximum transfer unit in bytes for this network interface.
 */
#define NET_DEVICE_INIT(dev_name, drv_name, init_fn, pm_action_cb,	\
			data, cfg, prio, api, l2,			\
			l2_ctx_type, mtu)				\
	Z_NET_DEVICE_INIT(DT_INVALID_NODE, dev_name, drv_name, init_fn,	\
			pm_action_cb, data, cfg, prio, api, l2,	\
			l2_ctx_type, mtu)

/**
 * @def NET_DEVICE_DT_DEFINE
 *
 * @brief Like NET_DEVICE_INIT but taking metadata from a devicetree node.
 * Create a network interface and bind it to network device.
 *
 * @param node_id The devicetree node identifier.
 * @param init_fn Address to the init function of the driver.
 * @param pm_action_cb Pointer to PM action callback.
 * Can be NULL if not implemented.
 * @param data Pointer to the device's private data.
 * @param cfg The address to the structure containing the
 * configuration information for this instance of the driver.
 * @param prio The initialization level at which configuration occurs.
 * @param api Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 * @param l2 Network L2 layer for this network interface.
 * @param l2_ctx_type Type of L2 context data.
 * @param mtu Maximum transfer unit in bytes for this network interface.
 */
#define NET_DEVICE_DT_DEFINE(node_id, init_fn, pm_action_cb, data, cfg,	\
			   prio, api, l2, l2_ctx_type, mtu)		\
	Z_NET_DEVICE_INIT(node_id, Z_DEVICE_DT_DEV_NAME(node_id),	\
			  DT_PROP_OR(node_id, label, ""), init_fn,	\
			  pm_action_cb, data, cfg, prio, api, l2,	\
			  l2_ctx_type, mtu)

/**
 * @def NET_DEVICE_DT_INST_DEFINE
 *
 * @brief Like NET_DEVICE_DT_DEFINE for an instance of a DT_DRV_COMPAT compatible
 *
 * @param inst instance number.  This is replaced by
 * <tt>DT_DRV_COMPAT(inst)</tt> in the call to NET_DEVICE_DT_DEFINE.
 *
 * @param ... other parameters as expected by NET_DEVICE_DT_DEFINE.
 */
#define NET_DEVICE_DT_INST_DEFINE(inst, ...) \
	NET_DEVICE_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__)

#define Z_NET_DEVICE_INIT_INSTANCE(node_id, dev_name, drv_name,		\
				   instance, init_fn, pm_action_cb,	\
				   data, cfg, prio, api, l2,		\
				   l2_ctx_type, mtu)			\
	Z_DEVICE_STATE_DEFINE(node_id, dev_name)			\
	Z_DEVICE_DEFINE(node_id, dev_name, drv_name, init_fn,		\
			pm_action_cb, data, cfg, POST_KERNEL,		\
			prio, api, &Z_DEVICE_STATE_NAME(dev_name));	\
	NET_L2_DATA_INIT(dev_name, instance, l2_ctx_type);		\
	NET_IF_INIT(dev_name, instance, l2, mtu, NET_IF_MAX_CONFIGS)

/**
 * @def NET_DEVICE_INIT_INSTANCE
 *
 * @brief Create multiple network interfaces and bind them to network device.
 * If your network device needs more than one instance of a network interface,
 * use this macro below and provide a different instance suffix each time
 * (0, 1, 2, ... or a, b, c ... whatever works for you)
 *
 * @param dev_name Network device name.
 * @param drv_name The name this instance of the driver exposes to
 * the system.
 * @param instance Instance identifier.
 * @param init_fn Address to the init function of the driver.
 * @param pm_action_cb Pointer to PM action callback.
 * Can be NULL if not implemented.
 * @param data Pointer to the device's private data.
 * @param cfg The address to the structure containing the
 * configuration information for this instance of the driver.
 * @param prio The initialization level at which configuration occurs.
 * @param api Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 * @param l2 Network L2 layer for this network interface.
 * @param l2_ctx_type Type of L2 context data.
 * @param mtu Maximum transfer unit in bytes for this network interface.
 */
#define NET_DEVICE_INIT_INSTANCE(dev_name, drv_name, instance, init_fn,	\
				 pm_action_cb, data, cfg, prio,	\
				 api, l2, l2_ctx_type, mtu)		\
	Z_NET_DEVICE_INIT_INSTANCE(DT_INVALID_NODE, dev_name, drv_name,	\
				   instance, init_fn, pm_action_cb,	\
				   data, cfg, prio, api, l2,		\
				   l2_ctx_type, mtu)

/**
 * @def NET_DEVICE_DT_DEFINE_INSTANCE
 *
 * @brief Like NET_DEVICE_OFFLOAD_INIT but taking metadata from a devicetree.
 * Create multiple network interfaces and bind them to network device.
 * If your network device needs more than one instance of a network interface,
 * use this macro below and provide a different instance suffix each time
 * (0, 1, 2, ... or a, b, c ... whatever works for you)
 *
 * @param node_id The devicetree node identifier.
 * @param instance Instance identifier.
 * @param init_fn Address to the init function of the driver.
 * @param pm_action_cb Pointer to PM action callback.
 * Can be NULL if not implemented.
 * @param data Pointer to the device's private data.
 * @param cfg The address to the structure containing the
 * configuration information for this instance of the driver.
 * @param prio The initialization level at which configuration occurs.
 * @param api Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 * @param l2 Network L2 layer for this network interface.
 * @param l2_ctx_type Type of L2 context data.
 * @param mtu Maximum transfer unit in bytes for this network interface.
 */
#define NET_DEVICE_DT_DEFINE_INSTANCE(node_id, instance, init_fn,	\
				      pm_action_cb, data, cfg, prio,	\
				      api, l2, l2_ctx_type, mtu)	\
	Z_NET_DEVICE_INIT_INSTANCE(node_id,				\
				   Z_DEVICE_DT_DEV_NAME(node_id),	\
				   DT_LABEL(node_id), instance,		\
				   pm_action_cb, data, cfg, prio, api,	\
				   l2, l2_ctx_type, mtu)

/**
 * @def NET_DEVICE_DT_INST_DEFINE_INSTANCE
 *
 * @brief Like NET_DEVICE_DT_DEFINE_INSTANCE for an instance of a DT_DRV_COMPAT
 * compatible
 *
 * @param inst instance number.  This is replaced by
 * <tt>DT_DRV_COMPAT(inst)</tt> in the call to NET_DEVICE_DT_DEFINE_INSTANCE.
 *
 * @param ... other parameters as expected by NET_DEVICE_DT_DEFINE_INSTANCE.
 */
#define NET_DEVICE_DT_INST_DEFINE_INSTANCE(inst, ...) \
	NET_DEVICE_DT_DEFINE_INSTANCE(DT_DRV_INST(inst), __VA_ARGS__)

#define Z_NET_DEVICE_OFFLOAD_INIT(node_id, dev_name, drv_name, init_fn,	\
				  pm_action_cb, data, cfg, prio,	\
				  api, mtu)				\
	Z_DEVICE_STATE_DEFINE(node_id, dev_name)			\
	Z_DEVICE_DEFINE(node_id, dev_name, drv_name, init_fn,		\
		pm_action_cb, data, cfg, POST_KERNEL, prio, api,	\
		&Z_DEVICE_STATE_NAME(dev_name));			\
	NET_IF_OFFLOAD_INIT(dev_name, 0, mtu)

/**
 * @def NET_DEVICE_OFFLOAD_INIT
 *
 * @brief Create a offloaded network interface and bind it to network device.
 * The offloaded network interface is implemented by a device vendor HAL or
 * similar.
 *
 * @param dev_name Network device name.
 * @param drv_name The name this instance of the driver exposes to
 * the system.
 * @param init_fn Address to the init function of the driver.
 * @param pm_action_cb Pointer to PM action callback.
 * Can be NULL if not implemented.
 * @param data Pointer to the device's private data.
 * @param cfg The address to the structure containing the
 * configuration information for this instance of the driver.
 * @param prio The initialization level at which configuration occurs.
 * @param api Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 * @param mtu Maximum transfer unit in bytes for this network interface.
 */
#define NET_DEVICE_OFFLOAD_INIT(dev_name, drv_name, init_fn,		\
				pm_action_cb, data, cfg, prio, api, mtu)\
	Z_NET_DEVICE_OFFLOAD_INIT(DT_INVALID_NODE, dev_name, drv_name,	\
				init_fn, pm_action_cb, data, cfg, prio,\
				api, mtu)

/**
 * @def NET_DEVICE_DT_OFFLOAD_DEFINE
 *
 * @brief Like NET_DEVICE_OFFLOAD_INIT but taking metadata from a devicetree
 * node. Create a offloaded network interface and bind it to network device.
 * The offloaded network interface is implemented by a device vendor HAL or
 * similar.
 *
 * @param node_id The devicetree node identifier.
 * @param init_fn Address to the init function of the driver.
 * @param pm_action_cb Pointer to PM action callback.
 * Can be NULL if not implemented.
 * @param data Pointer to the device's private data.
 * @param cfg The address to the structure containing the
 * configuration information for this instance of the driver.
 * @param prio The initialization level at which configuration occurs.
 * @param api Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 * @param mtu Maximum transfer unit in bytes for this network interface.
 */
#define NET_DEVICE_DT_OFFLOAD_DEFINE(node_id, init_fn, pm_action_cb,	\
				   data, cfg, prio, api, mtu)		\
	Z_NET_DEVICE_OFFLOAD_INIT(node_id, Z_DEVICE_DT_DEV_NAME(node_id), \
				  DT_PROP_OR(node_id, label, NULL),	\
				  init_fn, pm_action_cb, data, cfg,	\
				  prio, api, mtu)

/**
 * @def NET_DEVICE_DT_INST_OFFLOAD_DEFINE
 *
 * @brief Like NET_DEVICE_DT_OFFLOAD_DEFINE for an instance of a DT_DRV_COMPAT
 * compatible
 *
 * @param inst instance number.  This is replaced by
 * <tt>DT_DRV_COMPAT(inst)</tt> in the call to NET_DEVICE_DT_OFFLOAD_DEFINE.
 *
 * @param ... other parameters as expected by NET_DEVICE_DT_OFFLOAD_DEFINE.
 */
#define NET_DEVICE_DT_INST_OFFLOAD_DEFINE(inst, ...) \
	NET_DEVICE_DT_OFFLOAD_DEFINE(DT_DRV_INST(inst), __VA_ARGS__)

#ifdef __cplusplus
}
#endif

#include <syscalls/net_if.h>

/**
 * @}
 */

#endif /* ZEPHYR_INCLUDE_NET_NET_IF_H_ */
