1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief API for defining conn_mgr connectivity implementations (allowing ifaces to be used with
10 * conn_mgr_connectivity).
11 */
12
13 #ifndef ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_IMPL_H_
14 #define ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_IMPL_H_
15
16 #include <zephyr/device.h>
17 #include <zephyr/net/net_if.h>
18 #include <zephyr/sys/iterable_sections.h>
19 #include <zephyr/net/net_mgmt.h>
20 #include <zephyr/net/conn_mgr_connectivity.h>
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 /**
27 * @brief Connection Manager Connectivity Implementation API
28 * @defgroup conn_mgr_connectivity_impl Connection Manager Connectivity Implementation API
29 * @ingroup networking
30 * @{
31 */
32
33 /* Forward declaration */
34 struct conn_mgr_conn_binding;
35
36 /**
37 * @brief Connectivity Manager Connectivity API structure
38 *
39 * Used to provide generic access to network association parameters and procedures
40 */
41 struct conn_mgr_conn_api {
42 /**
43 * @brief When called, the connectivity implementation should start attempting to
44 * establish connectivity (association with a network) for the bound iface pointed
45 * to by if_conn->iface.
46 *
47 * Must be non-blocking.
48 *
49 * Called by @ref conn_mgr_if_connect.
50 */
51 int (*connect)(struct conn_mgr_conn_binding *const binding);
52
53 /**
54 * @brief When called, the connectivity implementation should disconnect (dissasociate), or
55 * stop any in-progress attempts to associate to a network, the bound iface pointed to by
56 * if_conn->iface.
57 *
58 * Must be non-blocking.
59 *
60 * Called by @ref conn_mgr_if_disconnect.
61 */
62 int (*disconnect)(struct conn_mgr_conn_binding *const binding);
63
64 /**
65 * @brief Called once for each iface that has been bound to a connectivity implementation
66 * using this API.
67 *
68 * Connectivity implementations should use this callback to perform any required
69 * per-bound-iface initialization.
70 *
71 * Implementations may choose to gracefully handle invalid buffer lengths with partial
72 * writes, rather than raise errors, if deemed appropriate.
73 */
74 void (*init)(struct conn_mgr_conn_binding *const binding);
75
76 /**
77 * @brief Implementation callback for conn_mgr_if_set_opt.
78 *
79 * Used to set implementation-specific connectivity settings.
80 *
81 * Calls to conn_mgr_if_set_opt on an iface will result in calls to this callback with
82 * the conn_mgr_conn_binding struct bound to that iface.
83 *
84 * It is up to the connectivity implementation to interpret optname. Options can be
85 * specific to the bound iface (pointed to by if_conn->iface), or can apply to the whole
86 * connectivity implementation.
87 *
88 * See the description of conn_mgr_if_set_opt for more details.
89 * set_opt implementations should conform to that description.
90 *
91 * Implementations may choose to gracefully handle invalid buffer lengths with partial
92 * reads, rather than raise errors, if deemed appropriate.
93 */
94 int (*set_opt)(struct conn_mgr_conn_binding *const binding,
95 int optname, const void *optval, size_t optlen);
96
97 /**
98 * @brief Implementation callback for conn_mgr_if_get_opt.
99 *
100 * Used to retrieve implementation-specific connectivity settings.
101 *
102 * Calls to conn_mgr_if_get_opt on an iface will result in calls to this callback with
103 * the conn_mgr_conn_binding struct bound to that iface.
104 *
105 * It is up to the connectivity implementation to interpret optname. Options can be
106 * specific to the bound iface (pointed to by if_conn->iface), or can apply to the whole
107 * connectivity implementation.
108 *
109 * See the description of conn_mgr_if_get_opt for more details.
110 * get_opt implementations should conform to that description.
111 */
112 int (*get_opt)(struct conn_mgr_conn_binding *const binding,
113 int optname, void *optval, size_t *optlen);
114 };
115
116 /** @cond INTERNAL_HIDDEN */
117 #define CONN_MGR_CONN_IMPL_GET_NAME(conn_id) __conn_mgr_conn_##conn_id
118 #define CONN_MGR_CONN_IMPL_GET_CTX_TYPE(conn_id) conn_id##_CTX_TYPE
119 /** @endcond */
120
121 /**
122 * @brief Connectivity Implementation struct
123 *
124 * Declares a conn_mgr connectivity layer implementation with the provided API
125 */
126 struct conn_mgr_conn_impl {
127 /** The connectivity API used by the implementation */
128 struct conn_mgr_conn_api *api;
129 };
130
131 /**
132 * @brief Define a conn_mgr connectivity implementation that can be bound to network devices.
133 *
134 * @param conn_id The name of the new connectivity implementation
135 * @param conn_api A pointer to a conn_mgr_conn_api struct
136 */
137 #define CONN_MGR_CONN_DEFINE(conn_id, conn_api) \
138 const struct conn_mgr_conn_impl CONN_MGR_CONN_IMPL_GET_NAME(conn_id) = { \
139 .api = conn_api, \
140 };
141
142 /**
143 * @brief Helper macro to make a conn_mgr connectivity implementation publicly available.
144 */
145 #define CONN_MGR_CONN_DECLARE_PUBLIC(conn_id) \
146 extern const struct conn_mgr_conn_impl CONN_MGR_CONN_IMPL_GET_NAME(conn_id)
147
148 /** @cond INTERNAL_HIDDEN */
149 #define CONN_MGR_CONN_BINDING_GET_NAME(dev_id, sfx) __conn_mgr_bndg_##dev_id##_##sfx
150 #define CONN_MGR_CONN_BINDING_GET_DATA(dev_id, sfx) __conn_mgr_bndg_data_##dev_id##_##sfx
151 #define CONN_MGR_CONN_BINDING_GET_MUTEX(dev_id, sfx) __conn_mgr_bndg_mutex_##dev_id##_##sfx
152 /** @endcond */
153
154 /**
155 * @brief Connectivity Manager network interface binding structure
156 *
157 * Binds a conn_mgr connectivity implementation to an iface / network device.
158 * Stores per-iface state for the connectivity implementation.
159 */
160 struct conn_mgr_conn_binding {
161 /** The network interface the connectivity implementation is bound to */
162 struct net_if *iface;
163
164 /** The connectivity implementation the network device is bound to */
165 const struct conn_mgr_conn_impl *impl;
166
167 /** Pointer to private, per-iface connectivity context */
168 void *ctx;
169
170 /**
171 * @name Generic connectivity state
172 * @{
173 */
174
175 /**
176 * Connectivity flags
177 *
178 * Public boolean state and configuration values supported by all bindings.
179 * See conn_mgr_if_flag for options.
180 */
181 uint32_t flags;
182
183 /**
184 * Timeout (seconds)
185 *
186 * Indicates to the connectivity implementation how long it should attempt to
187 * establish connectivity for during a connection attempt before giving up.
188 *
189 * The connectivity implementation should give up on establishing connectivity after this
190 * timeout, even if persistence is enabled.
191 *
192 * Set to @ref CONN_MGR_IF_NO_TIMEOUT to indicate that no timeout should be used.
193 */
194 int timeout;
195
196 /** @} */
197
198 /** @cond INTERNAL_HIDDEN */
199 /* Internal-use mutex for protecting access to the binding and API functions. */
200 struct k_mutex *mutex;
201 /** @endcond */
202 };
203
204 /**
205 * @brief Associate a connectivity implementation with an existing network device instance
206 *
207 * @param dev_id Network device id.
208 * @param inst Network device instance.
209 * @param conn_id Name of the connectivity implementation to associate.
210 */
211 #define CONN_MGR_BIND_CONN_INST(dev_id, inst, conn_id) \
212 K_MUTEX_DEFINE(CONN_MGR_CONN_BINDING_GET_MUTEX(dev_id, inst)); \
213 static CONN_MGR_CONN_IMPL_GET_CTX_TYPE(conn_id) \
214 CONN_MGR_CONN_BINDING_GET_DATA(dev_id, inst); \
215 static STRUCT_SECTION_ITERABLE(conn_mgr_conn_binding, \
216 CONN_MGR_CONN_BINDING_GET_NAME(dev_id, inst)) = { \
217 .iface = NET_IF_GET(dev_id, inst), \
218 .impl = &(CONN_MGR_CONN_IMPL_GET_NAME(conn_id)), \
219 .ctx = &(CONN_MGR_CONN_BINDING_GET_DATA(dev_id, inst)), \
220 .mutex = &(CONN_MGR_CONN_BINDING_GET_MUTEX(dev_id, inst)) \
221 };
222
223 /**
224 * @brief Associate a connectivity implementation with an existing network device
225 *
226 * @param dev_id Network device id.
227 * @param conn_id Name of the connectivity implementation to associate.
228 */
229 #define CONN_MGR_BIND_CONN(dev_id, conn_id) \
230 CONN_MGR_BIND_CONN_INST(dev_id, 0, conn_id)
231
232 /**
233 * @brief Retrieves the conn_mgr binding struct for a provided iface if it exists.
234 *
235 * Bindings for connectivity implementations with missing API structs are ignored.
236 *
237 * For use only by connectivity implementations.
238 *
239 * @param iface - bound network interface to obtain the binding struct for.
240 * @return struct conn_mgr_conn_binding* Pointer to the retrieved binding struct if it exists,
241 * NULL otherwise.
242 */
conn_mgr_if_get_binding(struct net_if * iface)243 static inline struct conn_mgr_conn_binding *conn_mgr_if_get_binding(struct net_if *iface)
244 {
245 STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) {
246 if (iface == binding->iface) {
247 if (binding->impl->api) {
248 return binding;
249 }
250 return NULL;
251 }
252 }
253 return NULL;
254 }
255
256 /**
257 * @brief Lock the passed-in binding, making it safe to access.
258 *
259 * Call this whenever accessing binding data, unless inside a conn_mgr_conn_api callback, where it
260 * is called automatically by conn_mgr.
261 *
262 * Reentrant.
263 *
264 * For use only by connectivity implementations.
265 *
266 * @param binding - Binding to lock
267 */
conn_mgr_binding_lock(struct conn_mgr_conn_binding * binding)268 static inline void conn_mgr_binding_lock(struct conn_mgr_conn_binding *binding)
269 {
270 (void)k_mutex_lock(binding->mutex, K_FOREVER);
271 }
272
273 /**
274 * @brief Unlocks the passed-in binding.
275 *
276 * Call this after any call to @ref conn_mgr_binding_lock once done accessing binding data.
277 *
278 * Reentrant.
279 *
280 * For use only by connectivity implementations.
281 *
282 * @param binding - Binding to unlock
283 */
conn_mgr_binding_unlock(struct conn_mgr_conn_binding * binding)284 static inline void conn_mgr_binding_unlock(struct conn_mgr_conn_binding *binding)
285 {
286 (void)k_mutex_unlock(binding->mutex);
287 }
288
289 /**
290 * @brief Set the value of the specified connectivity flag for the provided binding
291 *
292 * Can be used from any thread or callback without calling @ref conn_mgr_binding_lock.
293 *
294 * For use only by connectivity implementations
295 *
296 * @param binding The binding to check
297 * @param flag The flag to check
298 * @param value New value for the specified flag
299 */
conn_mgr_binding_set_flag(struct conn_mgr_conn_binding * binding,enum conn_mgr_if_flag flag,bool value)300 static inline void conn_mgr_binding_set_flag(struct conn_mgr_conn_binding *binding,
301 enum conn_mgr_if_flag flag, bool value)
302 {
303 conn_mgr_binding_lock(binding);
304
305 binding->flags &= ~BIT(flag);
306 if (value) {
307 binding->flags |= BIT(flag);
308 }
309
310 conn_mgr_binding_unlock(binding);
311 }
312
313 /**
314 * @brief Check the value of the specified connectivity flag for the provided binding
315 *
316 * Can be used from any thread or callback without calling @ref conn_mgr_binding_lock.
317 *
318 * For use only by connectivity implementations
319 *
320 * @param binding The binding to check
321 * @param flag The flag to check
322 * @return bool The value of the specified flag
323 */
conn_mgr_binding_get_flag(struct conn_mgr_conn_binding * binding,enum conn_mgr_if_flag flag)324 static inline bool conn_mgr_binding_get_flag(struct conn_mgr_conn_binding *binding,
325 enum conn_mgr_if_flag flag)
326 {
327 bool value = false;
328
329 conn_mgr_binding_lock(binding);
330
331 value = !!(binding->flags & BIT(flag));
332
333 conn_mgr_binding_unlock(binding);
334
335 return value;
336 }
337
338 /**
339 * @}
340 */
341
342 #ifdef __cplusplus
343 }
344 #endif
345
346 #endif /* ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_IMPL_H_ */
347