1 /** @file
2  *  @brief IPv6 neighbor management.
3  */
4 
5 /*
6  * Copyright (c) 2016 Intel Corporation
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 #ifndef __NET_NBR_H
11 #define __NET_NBR_H
12 
13 #include <stddef.h>
14 #include <zephyr/types.h>
15 #include <stdbool.h>
16 
17 #include <zephyr/net/net_if.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 #define NET_NBR_LLADDR_UNKNOWN 0xff
24 
25 /* The neighbors are tracked by link layer address. This is not part
26  * of struct net_nbr because this data can be shared between different
27  * neighboring tables.
28  */
29 struct net_nbr_lladdr {
30 	/** Link layer address */
31 	struct net_linkaddr_storage lladdr;
32 
33 	/** Reference count. */
34 	uint8_t ref;
35 };
36 
37 #define NET_NBR_LLADDR_INIT(_name, _count)	\
38 	struct net_nbr_lladdr _name[_count] = { }
39 
40 /* Alignment needed for various parts of the neighbor definition */
41 #define __net_nbr_align __aligned(sizeof(int))
42 
43 /* The neighbor node generic data. There can be sub-system specific
44  * data at the end of the node.
45  */
46 struct net_nbr {
47 	/** Reference count. */
48 	uint8_t ref;
49 
50 	/** Link to ll address. This is the index into lladdr array.
51 	 * The value NET_NBR_LLADDR_UNKNOWN tells that this neighbor
52 	 * does not yet have lladdr linked to it.
53 	 */
54 	uint8_t idx;
55 
56 	/** Amount of data that this neighbor buffer can store. */
57 	const uint16_t size;
58 
59 	/** Extra data size associated with this neighbor */
60 	const uint16_t extra_data_size;
61 
62 	/** Interface this neighbor is found */
63 	struct net_if *iface;
64 
65 	/** Pointer to the start of data in the neighbor table. */
66 	uint8_t *data;
67 
68 	/** Function to be called when the neighbor is removed. */
69 	void (*const remove)(struct net_nbr *nbr);
70 
71 	/** Start of the data storage. Not to be accessed directly
72 	 *  (the data pointer should be used instead).
73 	 */
74 	uint8_t __nbr[0] __net_nbr_align;
75 };
76 
77 /* This is an array of struct net_nbr + some additional data */
78 #define NET_NBR_POOL_INIT(_name, _count, _size, _remove, _extra_size)	\
79 	struct {							\
80 		struct net_nbr nbr;					\
81 		uint8_t data[ROUND_UP(_size, 4)] __net_nbr_align;	\
82 		uint8_t extra[ROUND_UP(_extra_size, 4)] __net_nbr_align;\
83 	} _name[_count] = {						\
84 		[0 ... (_count - 1)] = { .nbr = {			\
85 			.idx = NET_NBR_LLADDR_UNKNOWN,			\
86 			.remove = _remove,				\
87 			.size = ROUND_UP(_size, 4),			\
88 			.extra_data_size = ROUND_UP(_extra_size, 4) } },\
89 	}
90 
91 struct net_nbr_table {
92 	/** Link to a neighbor pool */
93 	struct net_nbr *nbr;
94 
95 	/** Function to be called when the table is cleared. */
96 	void (*const clear)(struct net_nbr_table *table);
97 
98 	/** Max number of neighbors in the pool */
99 	const uint16_t nbr_count;
100 };
101 
102 #define NET_NBR_LOCAL static
103 #define NET_NBR_GLOBAL
104 
105 /* Type of the table can be NET_NBR_LOCAL or NET_NBR_GLOBAL
106  */
107 #define NET_NBR_TABLE_INIT(_type, _name, _pool, _clear)			\
108 	_type struct net_nbr_table_##_name {				\
109 		struct net_nbr_table table;				\
110 	} net_##_name __used = {					\
111 		.table = {						\
112 			.clear = _clear,				\
113 			.nbr = (struct net_nbr *)_pool,			\
114 			.nbr_count = ARRAY_SIZE(_pool),			\
115 		}							\
116 	}
117 
118 /**
119  *  @brief Get a pointer to the extra data of a neighbor entry.
120  *
121  *  @param nbr A valid pointer to neighbor
122  *
123  *  @return Pointer to the extra data of the nbr.
124  */
net_nbr_extra_data(struct net_nbr * nbr)125 static inline void *net_nbr_extra_data(struct net_nbr *nbr)
126 {
127 	return (void *)ROUND_UP((nbr->__nbr + nbr->size), sizeof(int));
128 }
129 
130 /**
131  * @brief Decrement the reference count. If count goes to 0, the neighbor
132  * is released and returned to free list.
133  * @param nbr Pointer to neighbor
134  */
135 #if defined(CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_DBG)
136 void net_nbr_unref_debug(struct net_nbr *nbr, const char *caller, int line);
137 #define net_nbr_unref(nbr) net_nbr_unref_debug(nbr, __func__, __LINE__)
138 #else
139 void net_nbr_unref(struct net_nbr *nbr);
140 #endif
141 
142 /**
143  * @brief Increment the reference count.
144  * @param nbr Pointer to neighbor
145  * @return Pointer to neighbor
146  */
147 #if defined(CONFIG_NET_IPV6_NBR_CACHE_LOG_LEVEL_DBG)
148 struct net_nbr *net_nbr_ref_debug(struct net_nbr *nbr, const char *caller,
149 				  int line);
150 #define net_nbr_ref(nbr) net_nbr_ref_debug(nbr, __func__, __LINE__)
151 #else
152 struct net_nbr *net_nbr_ref(struct net_nbr *nbr);
153 #endif
154 
155 /**
156  * @brief Get a free neighbor from specific table.
157  * @param table Neighbor table
158  * @return Pointer to neighbor, NULL if no free neighbors
159  */
160 struct net_nbr *net_nbr_get(struct net_nbr_table *table);
161 
162 /**
163  * @brief Find a neighbor from specific table.
164  * @param table Neighbor table
165  * @param iface Network interface to use
166  * @param lladdr Neighbor link layer address
167  * @return Pointer to neighbor, NULL if not found
168  */
169 struct net_nbr *net_nbr_lookup(struct net_nbr_table *table,
170 			       struct net_if *iface,
171 			       struct net_linkaddr *lladdr);
172 
173 /**
174  * @brief Link a neighbor to specific link layer address.
175  * @param table Neighbor table
176  * @param iface Network interface to use
177  * @param lladdr Neighbor link layer address
178  * @return 0 if ok, <0 if linking failed
179  */
180 int net_nbr_link(struct net_nbr *nbr, struct net_if *iface,
181 		 const struct net_linkaddr *lladdr);
182 
183 /**
184  * @brief Unlink a neighbor from specific link layer address.
185  * @param table Neighbor table
186  * @param lladdr Neighbor link layer address
187  * @return 0 if ok, <0 if unlinking failed
188  */
189 int net_nbr_unlink(struct net_nbr *nbr, struct net_linkaddr *lladdr);
190 
191 /**
192  * @brief Return link address for a specific lladdr table index
193  * @param idx Link layer address index in ll table.
194  * @return Pointer to link layer address storage, NULL if not found
195  */
196 #if defined(CONFIG_NET_NATIVE)
197 struct net_linkaddr_storage *net_nbr_get_lladdr(uint8_t idx);
198 #else
net_nbr_get_lladdr(uint8_t idx)199 static inline struct net_linkaddr_storage *net_nbr_get_lladdr(uint8_t idx)
200 {
201 	ARG_UNUSED(idx);
202 
203 	return NULL;
204 }
205 #endif
206 
207 /**
208  * @brief Clear table from all neighbors. After this the linking between
209  * lladdr and neighbor is removed.
210  * @param table Neighbor table
211  */
212 void net_nbr_clear_table(struct net_nbr_table *table);
213 
214 /**
215  * @brief Debug helper to print out the neighbor information.
216  * @param table Neighbor table
217  */
218 void net_nbr_print(struct net_nbr_table *table);
219 
220 #ifdef __cplusplus
221 }
222 #endif
223 
224 #endif /* __NET_NBR_H */
225