blob: 51b826d3491498415d6fdbf7d8ddc36b6a5be5a6 [file] [log] [blame]
/*
* 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_ */