Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/** @file
 *  @brief IPv6 neighbor management.
 */

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef __NET_NBR_H
#define __NET_NBR_H

#include <stddef.h>
#include <zephyr/types.h>
#include <stdbool.h>

#include <net/net_if.h>

#ifdef __cplusplus
extern "C" {
#endif

#define NET_NBR_LLADDR_UNKNOWN 0xff

/* The neighbors are tracked by link layer address. This is not part
 * of struct net_nbr because this data can be shared between different
 * neighboring tables.
 */
struct net_nbr_lladdr {
	/** Link layer address */
	struct net_linkaddr_storage lladdr;

	/** Reference count. */
	uint8_t ref;
};

#define NET_NBR_LLADDR_INIT(_name, _count)	\
	struct net_nbr_lladdr _name[_count] = { }

/* Alignment needed for various parts of the neighbor definition */
#define __net_nbr_align __aligned(sizeof(int))

/* The neighbor node generic data. There can be sub-system specific
 * data at the end of the node.
 */
struct net_nbr {
	/** Reference count. */
	uint8_t ref;

	/** Link to ll address. This is the index into lladdr array.
	 * The value NET_NBR_LLADDR_UNKNOWN tells that this neighbor
	 * does not yet have lladdr linked to it.
	 */
	uint8_t idx;

	/** Amount of data that this neighbor buffer can store. */
	const uint16_t size;

	/** Extra data size associated with this neighbor */
	const uint16_t extra_data_size;

	/** Interface this neighbor is found */
	struct net_if *iface;

	/** Pointer to the start of data in the neighbor table. */
	uint8_t *data;

	/** Function to be called when the neighbor is removed. */
	void (*const remove)(struct net_nbr *nbr);

	/** Start of the data storage. Not to be accessed directly
	 *  (the data pointer should be used instead).
	 */
	uint8_t __nbr[0] __net_nbr_align;
};

/* This is an array of struct net_nbr + some additional data */
#define NET_NBR_POOL_INIT(_name, _count, _size, _remove, _extra_size)	\
	struct {							\
		struct net_nbr nbr;					\
		uint8_t data[ROUND_UP(_size, 4)] __net_nbr_align;	\
		uint8_t extra[ROUND_UP(_extra_size, 4)] __net_nbr_align;\
	} _name[_count] = {						\
		[0 ... (_count - 1)] = { .nbr = {			\
			.idx = NET_NBR_LLADDR_UNKNOWN,			\
			.remove = _remove,				\
			.size = ROUND_UP(_size, 4),			\
			.extra_data_size = ROUND_UP(_extra_size, 4) } },\
	}

struct net_nbr_table {
	/** Link to a neighbor pool */
	struct net_nbr *nbr;

	/** Function to be called when the table is cleared. */
	void (*const clear)(struct net_nbr_table *table);

	/** Max number of neighbors in the pool */
	const uint16_t nbr_count;
};

#define NET_NBR_LOCAL static
#define NET_NBR_GLOBAL

/* Type of the table can be NET_NBR_LOCAL or NET_NBR_GLOBAL
 */
#define NET_NBR_TABLE_INIT(_type, _name, _pool, _clear)			\
	_type struct net_nbr_table_##_name {				\
		struct net_nbr_table table;				\
	} net_##_name __used = {					\
		.table = {						\
			.clear = _clear,				\
			.nbr = (struct net_nbr *)_pool,			\
			.nbr_count = ARRAY_SIZE(_pool),			\
		}							\
	}

/**
 *  @brief Get a pointer to the extra data of a neighbor entry.
 *
 *  @param nbr A valid pointer to neighbor
 *
 *  @return Pointer to the extra data of the nbr.
 */
static inline void *net_nbr_extra_data(struct net_nbr *nbr)
{
	return (void *)ROUND_UP((nbr->__nbr + nbr->size), sizeof(int));
}

/**
 * @brief Decrement the reference count. If count goes to 0, the neighbor
 * is released and returned to free list.
 * @param nbr Pointer to neighbor
 */
#if defined(CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_DBG)
void net_nbr_unref_debug(struct net_nbr *nbr, const char *caller, int line);
#define net_nbr_unref(nbr) net_nbr_unref_debug(nbr, __func__, __LINE__)
#else
void net_nbr_unref(struct net_nbr *nbr);
#endif

/**
 * @brief Increment the reference count.
 * @param nbr Pointer to neighbor
 * @return Pointer to neighbor
 */
#if defined(CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_DBG)
struct net_nbr *net_nbr_ref_debug(struct net_nbr *nbr, const char *caller,
				  int line);
#define net_nbr_ref(nbr) net_nbr_ref_debug(nbr, __func__, __LINE__)
#else
struct net_nbr *net_nbr_ref(struct net_nbr *nbr);
#endif

/**
 * @brief Get a free neighbor from specific table.
 * @param table Neighbor table
 * @return Pointer to neighbor, NULL if no free neighbors
 */
struct net_nbr *net_nbr_get(struct net_nbr_table *table);

/**
 * @brief Find a neighbor from specific table.
 * @param table Neighbor table
 * @param iface Network interface to use
 * @param lladdr Neighbor link layer address
 * @return Pointer to neighbor, NULL if not found
 */
struct net_nbr *net_nbr_lookup(struct net_nbr_table *table,
			       struct net_if *iface,
			       struct net_linkaddr *lladdr);

/**
 * @brief Link a neighbor to specific link layer address.
 * @param table Neighbor table
 * @param iface Network interface to use
 * @param lladdr Neighbor link layer address
 * @return 0 if ok, <0 if linking failed
 */
int net_nbr_link(struct net_nbr *nbr, struct net_if *iface,
		 const struct net_linkaddr *lladdr);

/**
 * @brief Unlink a neighbor from specific link layer address.
 * @param table Neighbor table
 * @param lladdr Neighbor link layer address
 * @return 0 if ok, <0 if unlinking failed
 */
int net_nbr_unlink(struct net_nbr *nbr, struct net_linkaddr *lladdr);

/**
 * @brief Return link address for a specific lladdr table index
 * @param idx Link layer address index in ll table.
 * @return Pointer to link layer address storage, NULL if not found
 */
#if defined(CONFIG_NET_NATIVE)
struct net_linkaddr_storage *net_nbr_get_lladdr(uint8_t idx);
#else
static inline struct net_linkaddr_storage *net_nbr_get_lladdr(uint8_t idx)
{
	ARG_UNUSED(idx);

	return NULL;
}
#endif

/**
 * @brief Clear table from all neighbors. After this the linking between
 * lladdr and neighbor is removed.
 * @param table Neighbor table
 */
void net_nbr_clear_table(struct net_nbr_table *table);

/**
 * @brief Debug helper to print out the neighbor information.
 * @param table Neighbor table
 */
void net_nbr_print(struct net_nbr_table *table);

#ifdef __cplusplus
}
#endif

#endif /* __NET_NBR_H */