| /* |
| * Copyright (c) 2023 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** |
| * @file |
| * @brief API for defining conn_mgr connectivity implementations (allowing ifaces to be used with |
| * conn_mgr_connectivity). |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_IMPL_H_ |
| #define ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_IMPL_H_ |
| |
| #include <zephyr/device.h> |
| #include <zephyr/net/net_if.h> |
| #include <zephyr/sys/iterable_sections.h> |
| #include <zephyr/net/net_mgmt.h> |
| #include <zephyr/net/conn_mgr_connectivity.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @brief Connection Manager Connectivity Implementation API |
| * @defgroup conn_mgr_connectivity_impl Connection Manager Connectivity Implementation API |
| * @ingroup networking |
| * @{ |
| */ |
| |
| /* Forward declaration */ |
| struct conn_mgr_conn_binding; |
| |
| /** |
| * @brief Connectivity Manager Connectivity API structure |
| * |
| * Used to provide generic access to network association parameters and procedures |
| */ |
| struct conn_mgr_conn_api { |
| /** |
| * @brief When called, the connectivity implementation should start attempting to |
| * establish connectivity (association with a network) for the bound iface pointed |
| * to by if_conn->iface. |
| * |
| * Must be non-blocking. |
| * |
| * Called by @ref conn_mgr_if_connect. |
| */ |
| int (*connect)(struct conn_mgr_conn_binding *const binding); |
| |
| /** |
| * @brief When called, the connectivity implementation should disconnect (dissasociate), or |
| * stop any in-progress attempts to associate to a network, the bound iface pointed to by |
| * if_conn->iface. |
| * |
| * Must be non-blocking. |
| * |
| * Called by @ref conn_mgr_if_disconnect. |
| */ |
| int (*disconnect)(struct conn_mgr_conn_binding *const binding); |
| |
| /** |
| * @brief Called once for each iface that has been bound to a connectivity implementation |
| * using this API. |
| * |
| * Connectivity implementations should use this callback to perform any required |
| * per-bound-iface initialization. |
| * |
| * Implementations may choose to gracefully handle invalid buffer lengths with partial |
| * writes, rather than raise errors, if deemed appropriate. |
| */ |
| void (*init)(struct conn_mgr_conn_binding *const binding); |
| |
| /** |
| * @brief Implementation callback for conn_mgr_if_set_opt. |
| * |
| * Used to set implementation-specific connectivity settings. |
| * |
| * Calls to conn_mgr_if_set_opt on an iface will result in calls to this callback with |
| * the conn_mgr_conn_binding struct bound to that iface. |
| * |
| * It is up to the connectivity implementation to interpret optname. Options can be |
| * specific to the bound iface (pointed to by if_conn->iface), or can apply to the whole |
| * connectivity implementation. |
| * |
| * See the description of conn_mgr_if_set_opt for more details. |
| * set_opt implementations should conform to that description. |
| * |
| * Implementations may choose to gracefully handle invalid buffer lengths with partial |
| * reads, rather than raise errors, if deemed appropriate. |
| */ |
| int (*set_opt)(struct conn_mgr_conn_binding *const binding, |
| int optname, const void *optval, size_t optlen); |
| |
| /** |
| * @brief Implementation callback for conn_mgr_if_get_opt. |
| * |
| * Used to retrieve implementation-specific connectivity settings. |
| * |
| * Calls to conn_mgr_if_get_opt on an iface will result in calls to this callback with |
| * the conn_mgr_conn_binding struct bound to that iface. |
| * |
| * It is up to the connectivity implementation to interpret optname. Options can be |
| * specific to the bound iface (pointed to by if_conn->iface), or can apply to the whole |
| * connectivity implementation. |
| * |
| * See the description of conn_mgr_if_get_opt for more details. |
| * get_opt implementations should conform to that description. |
| */ |
| int (*get_opt)(struct conn_mgr_conn_binding *const binding, |
| int optname, void *optval, size_t *optlen); |
| }; |
| |
| /** @cond INTERNAL_HIDDEN */ |
| #define CONN_MGR_CONN_IMPL_GET_NAME(conn_id) __conn_mgr_conn_##conn_id |
| #define CONN_MGR_CONN_IMPL_GET_CTX_TYPE(conn_id) conn_id##_CTX_TYPE |
| /** @endcond */ |
| |
| /** |
| * @brief Connectivity Implementation struct |
| * |
| * Declares a conn_mgr connectivity layer implementation with the provided API |
| */ |
| struct conn_mgr_conn_impl { |
| /** The connectivity API used by the implementation */ |
| struct conn_mgr_conn_api *api; |
| }; |
| |
| /** |
| * @brief Define a conn_mgr connectivity implementation that can be bound to network devices. |
| * |
| * @param conn_id The name of the new connectivity implementation |
| * @param conn_api A pointer to a conn_mgr_conn_api struct |
| */ |
| #define CONN_MGR_CONN_DEFINE(conn_id, conn_api) \ |
| const struct conn_mgr_conn_impl CONN_MGR_CONN_IMPL_GET_NAME(conn_id) = { \ |
| .api = conn_api, \ |
| }; |
| |
| /** |
| * @brief Helper macro to make a conn_mgr connectivity implementation publicly available. |
| */ |
| #define CONN_MGR_CONN_DECLARE_PUBLIC(conn_id) \ |
| extern const struct conn_mgr_conn_impl CONN_MGR_CONN_IMPL_GET_NAME(conn_id) |
| |
| /** @cond INTERNAL_HIDDEN */ |
| #define CONN_MGR_CONN_BINDING_GET_NAME(dev_id, sfx) __conn_mgr_bndg_##dev_id##_##sfx |
| #define CONN_MGR_CONN_BINDING_GET_DATA(dev_id, sfx) __conn_mgr_bndg_data_##dev_id##_##sfx |
| #define CONN_MGR_CONN_BINDING_GET_MUTEX(dev_id, sfx) __conn_mgr_bndg_mutex_##dev_id##_##sfx |
| /** @endcond */ |
| |
| /** |
| * @brief Connectivity Manager network interface binding structure |
| * |
| * Binds a conn_mgr connectivity implementation to an iface / network device. |
| * Stores per-iface state for the connectivity implementation. |
| */ |
| struct conn_mgr_conn_binding { |
| /** The network interface the connectivity implementation is bound to */ |
| struct net_if *iface; |
| |
| /** The connectivity implementation the network device is bound to */ |
| const struct conn_mgr_conn_impl *impl; |
| |
| /** Pointer to private, per-iface connectivity context */ |
| void *ctx; |
| |
| /** |
| * @name Generic connectivity state |
| * @{ |
| */ |
| |
| /** |
| * Connectivity flags |
| * |
| * Public boolean state and configuration values supported by all bindings. |
| * See conn_mgr_if_flag for options. |
| */ |
| uint32_t flags; |
| |
| /** |
| * Timeout (seconds) |
| * |
| * Indicates to the connectivity implementation how long it should attempt to |
| * establish connectivity for during a connection attempt before giving up. |
| * |
| * The connectivity implementation should give up on establishing connectivity after this |
| * timeout, even if persistence is enabled. |
| * |
| * Set to @ref CONN_MGR_IF_NO_TIMEOUT to indicate that no timeout should be used. |
| */ |
| int timeout; |
| |
| /** @} */ |
| |
| /** @cond INTERNAL_HIDDEN */ |
| /* Internal-use mutex for protecting access to the binding and API functions. */ |
| struct k_mutex *mutex; |
| /** @endcond */ |
| }; |
| |
| /** |
| * @brief Associate a connectivity implementation with an existing network device instance |
| * |
| * @param dev_id Network device id. |
| * @param inst Network device instance. |
| * @param conn_id Name of the connectivity implementation to associate. |
| */ |
| #define CONN_MGR_BIND_CONN_INST(dev_id, inst, conn_id) \ |
| K_MUTEX_DEFINE(CONN_MGR_CONN_BINDING_GET_MUTEX(dev_id, inst)); \ |
| static CONN_MGR_CONN_IMPL_GET_CTX_TYPE(conn_id) \ |
| CONN_MGR_CONN_BINDING_GET_DATA(dev_id, inst); \ |
| static STRUCT_SECTION_ITERABLE(conn_mgr_conn_binding, \ |
| CONN_MGR_CONN_BINDING_GET_NAME(dev_id, inst)) = { \ |
| .iface = NET_IF_GET(dev_id, inst), \ |
| .impl = &(CONN_MGR_CONN_IMPL_GET_NAME(conn_id)), \ |
| .ctx = &(CONN_MGR_CONN_BINDING_GET_DATA(dev_id, inst)), \ |
| .mutex = &(CONN_MGR_CONN_BINDING_GET_MUTEX(dev_id, inst)) \ |
| }; |
| |
| /** |
| * @brief Associate a connectivity implementation with an existing network device |
| * |
| * @param dev_id Network device id. |
| * @param conn_id Name of the connectivity implementation to associate. |
| */ |
| #define CONN_MGR_BIND_CONN(dev_id, conn_id) \ |
| CONN_MGR_BIND_CONN_INST(dev_id, 0, conn_id) |
| |
| /** |
| * @brief Retrieves the conn_mgr binding struct for a provided iface if it exists. |
| * |
| * Bindings for connectivity implementations with missing API structs are ignored. |
| * |
| * For use only by connectivity implementations. |
| * |
| * @param iface - bound network interface to obtain the binding struct for. |
| * @return struct conn_mgr_conn_binding* Pointer to the retrieved binding struct if it exists, |
| * NULL otherwise. |
| */ |
| static inline struct conn_mgr_conn_binding *conn_mgr_if_get_binding(struct net_if *iface) |
| { |
| STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) { |
| if (iface == binding->iface) { |
| if (binding->impl->api) { |
| return binding; |
| } |
| return NULL; |
| } |
| } |
| return NULL; |
| } |
| |
| /** |
| * @brief Lock the passed-in binding, making it safe to access. |
| * |
| * Call this whenever accessing binding data, unless inside a conn_mgr_conn_api callback, where it |
| * is called automatically by conn_mgr. |
| * |
| * Reentrant. |
| * |
| * For use only by connectivity implementations. |
| * |
| * @param binding - Binding to lock |
| */ |
| static inline void conn_mgr_binding_lock(struct conn_mgr_conn_binding *binding) |
| { |
| (void)k_mutex_lock(binding->mutex, K_FOREVER); |
| } |
| |
| /** |
| * @brief Unlocks the passed-in binding. |
| * |
| * Call this after any call to @ref conn_mgr_binding_lock once done accessing binding data. |
| * |
| * Reentrant. |
| * |
| * For use only by connectivity implementations. |
| * |
| * @param binding - Binding to unlock |
| */ |
| static inline void conn_mgr_binding_unlock(struct conn_mgr_conn_binding *binding) |
| { |
| (void)k_mutex_unlock(binding->mutex); |
| } |
| |
| /** |
| * @brief Set the value of the specified connectivity flag for the provided binding |
| * |
| * Can be used from any thread or callback without calling @ref conn_mgr_binding_lock. |
| * |
| * For use only by connectivity implementations |
| * |
| * @param binding The binding to check |
| * @param flag The flag to check |
| * @param value New value for the specified flag |
| */ |
| static inline void conn_mgr_binding_set_flag(struct conn_mgr_conn_binding *binding, |
| enum conn_mgr_if_flag flag, bool value) |
| { |
| conn_mgr_binding_lock(binding); |
| |
| binding->flags &= ~BIT(flag); |
| if (value) { |
| binding->flags |= BIT(flag); |
| } |
| |
| conn_mgr_binding_unlock(binding); |
| } |
| |
| /** |
| * @brief Check the value of the specified connectivity flag for the provided binding |
| * |
| * Can be used from any thread or callback without calling @ref conn_mgr_binding_lock. |
| * |
| * For use only by connectivity implementations |
| * |
| * @param binding The binding to check |
| * @param flag The flag to check |
| * @return bool The value of the specified flag |
| */ |
| static inline bool conn_mgr_binding_get_flag(struct conn_mgr_conn_binding *binding, |
| enum conn_mgr_if_flag flag) |
| { |
| bool value = false; |
| |
| conn_mgr_binding_lock(binding); |
| |
| value = !!(binding->flags & BIT(flag)); |
| |
| conn_mgr_binding_unlock(binding); |
| |
| return value; |
| } |
| |
| /** |
| * @} |
| */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_IMPL_H_ */ |