blob: 34b885d86321ecb5bc843b965f286fe02b554b9b [file] [log] [blame]
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief API for defining generic interfaces for configuring and firing network association
* routines on network devices that support it.
*/
#ifndef ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_H_
#define ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_H_
#include <zephyr/device.h>
#include <zephyr/net/net_if.h>
#include <zephyr/sys/iterable_sections.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Connection Manager Connectivity API
* @defgroup conn_mgr_connectivity Connection Manager Connectivity API
* @ingroup networking
* @{
*/
/** @cond INTERNAL_HIDDEN */
/* Connectivity Events */
#define _NET_MGMT_CONN_LAYER NET_MGMT_LAYER(NET_MGMT_LAYER_L2)
#define _NET_MGMT_CONN_CODE NET_MGMT_LAYER_CODE(0x207)
#define _NET_MGMT_CONN_BASE (_NET_MGMT_CONN_LAYER | _NET_MGMT_CONN_CODE)
#define _NET_MGMT_CONN_IF_EVENT (NET_MGMT_IFACE_BIT | _NET_MGMT_CONN_BASE)
enum net_event_ethernet_cmd {
NET_EVENT_CONN_CMD_IF_TIMEOUT = 1,
NET_EVENT_CONN_CMD_IF_FATAL_ERROR,
};
#define NET_EVENT_CONN_IF_TIMEOUT \
(_NET_MGMT_CONN_IF_EVENT | NET_EVENT_CONN_CMD_IF_TIMEOUT)
#define NET_EVENT_CONN_IF_FATAL_ERROR \
(_NET_MGMT_CONN_IF_EVENT | NET_EVENT_CONN_CMD_IF_FATAL_ERROR)
/** @endcond */
/**
* @brief Connectivity Manager Connectivity API structure
*
* Used to provide generic access to network association parameters and procedures
*/
struct conn_mgr_conn_binding;
struct conn_mgr_conn_api {
/**
* @brief When called, the connectivity implementation should start attempting to
* establish connectivity for (associate with a network) the bound iface pointed
* to by if_conn->iface.
*
* Must be non-blocking.
*
* Called by 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 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 conn_mgr 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 Per-iface connectivity flags
*/
enum conn_mgr_if_flag {
/* Persistent
* When set, indicates that the connectivity implementation bound to this iface should
* attempt to persist connectivity by automatically reconnecting after connection loss.
*/
CONN_MGR_IF_PERSISTENT,
/** @cond INTERNAL_HIDDEN */
/* Total number of flags - must be at the end of the enum */
CONN_MGR_NUM_IF_FLAGS,
/** @endcond */
};
/* Value to use with conn_mgr_conn_binding->timeout to indicate no timeout */
#define CONN_MGR_IF_NO_TIMEOUT 0
/**
* @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;
/* Generic connectivity state - Flags
* Public boolean state and configuration values supported by all bindings.
* See conn_mgr_if_flag for options.
*/
uint32_t flags;
/* Generic connectivity state - 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 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 Connect interface
*
* If the provided iface has been bound to a connectivity implementation, initiate
* network connect/association.
*
* Automatically takes the iface admin-up (by calling net_if_up) if it isn't already.
*
* Non-Blocking.
*
* @param iface Pointer to network interface
* @retval 0 on success.
* @retval -ESHUTDOWN if the iface is not admin-up.
* @retval -ENOTSUP if the iface does not have a connectivity implementation.
* @retval implementation-specific status code otherwise.
*/
int conn_mgr_if_connect(struct net_if *iface);
/**
* @brief Disconnect interface
*
* If the provided iface has been bound to a connectivity implementation, disconnect/dissassociate
* it from the network, and cancel any pending attempts to connect/associate.
*
* Does nothing if the iface is currently admin-down.
*
* @param iface Pointer to network interface
*
* @retval 0 on success.
* @retval -ENOTSUP if the iface does not have a connectivity implementation.
* @retval implementation-specific status code otherwise.
*/
int conn_mgr_if_disconnect(struct net_if *iface);
/**
* @brief Check whether the provided network interface supports connectivity / has been bound
* to a connectivity implementation.
*
* @param iface Pointer to the iface to check.
* @retval true if connectivity is supported (a connectivity implementation has been bound).
* @retval false otherwise.
*/
bool conn_mgr_if_is_bound(struct net_if *iface);
/**
* @brief Set implementation-specific connectivity options.
*
* If the provided iface has been bound to a connectivity implementation that supports it,
* implementation-specific connectivity options related to the iface.
*
* @param iface Pointer to the network interface.
* @param optname Integer value representing the option to set.
* The meaning of values is up to the conn_mgr_conn_api implementation.
* Some settings may affect multiple ifaces.
* @param optval Pointer to the value to be assigned to the option.
* @param optlen Length (in bytes) of the value to be assigned to the option.
* @retval 0 if successful.
* @retval -ENOTSUP if conn_mgr_if_set_opt not implemented by the iface.
* @retval -ENOBUFS if optlen is too long.
* @retval -EINVAL if NULL optval pointer provided.
* @retval -ENOPROTOOPT if the optname is not recognized.
* @retval implementation-specific error code otherwise.
*/
int conn_mgr_if_set_opt(struct net_if *iface, int optname, const void *optval, size_t optlen);
/**
* @brief Get implementation-specific connectivity options.
*
* If the provided iface has been bound to a connectivity implementation that supports it,
* retrieves implementation-specific connectivity options related to the iface.
*
* @param iface Pointer to the network interface.
* @param optname Integer value representing the option to set.
* The meaning of values is up to the conn_mgr_conn_api implementation.
* Some settings may be shared by multiple ifaces.
* @param optval Pointer to where the retrieved value should be stored.
* @param optlen Pointer to length (in bytes) of the destination buffer available for storing the
* retrieved value. If the available space is less than what is needed, -ENOBUFS
* is returned. If the available space is invalid, -EINVAL is returned.
*
* optlen will always be set to the total number of bytes written, regardless of
* whether an error is returned, even if zero bytes were written.
*
* @retval 0 if successful.
* @retval -ENOTSUP if conn_mgr_if_get_opt is not implemented by the iface.
* @retval -ENOBUFS if retrieval buffer is too small.
* @retval -EINVAL if invalid retrieval buffer length is provided, or if NULL optval or
* optlen pointer provided.
* @retval -ENOPROTOOPT if the optname is not recognized.
* @retval implementation-specific error code otherwise.
*/
int conn_mgr_if_get_opt(struct net_if *iface, int optname, void *optval, size_t *optlen);
/**
* @brief Check the value of connectivity flags
*
* If the provided iface is bound to a connectivity implementation, retrieves the value of the
* specified connectivity flag associated with that iface.
*
* @param iface - Pointer to the network interface to check.
* @param flag - The flag to check.
* @return True if the flag is set, otherwise False.
* Also returns False if the provided iface is not bound to a connectivity implementation,
* or the requested flag doesn't exist.
*/
bool conn_mgr_if_get_flag(struct net_if *iface, enum conn_mgr_if_flag flag);
/**
* @brief Set the value of a connectivity flags
*
* If the provided iface is bound to a connectivity implementation, sets the value of the
* specified connectivity flag associated with that iface.
*
* @param iface - Pointer to the network interface to modify.
* @param flag - The flag to set.
* @param value - Whether the flag should be enabled or disabled.
* @retval 0 on success.
* @retval -EINVAL if the flag does not exist.
* @retval -ENOTSUP if the provided iface is not bound to a connectivity implementation.
*/
int conn_mgr_if_set_flag(struct net_if *iface, enum conn_mgr_if_flag flag, bool value);
/**
* @brief Get the connectivity timeout for an iface
*
* If the provided iface is bound to a connectivity implementation, retrieves the timeout setting
* in seconds for it.
*
* @param iface - Pointer to the iface to check.
* @return int - The connectivity timeout value (in seconds) if it could be retrieved, otherwise
* CONN_MGR_IF_NO_TIMEOUT.
*/
int conn_mgr_if_get_timeout(struct net_if *iface);
/**
* @brief Set the connectivity timeout for an iface.
*
* If the provided iface is bound to a connectivity implementation, sets the timeout setting in
* seconds for it.
*
* @param iface - Pointer to the network interface to modify.
* @param timeout - The timeout value to set (in seconds).
* Pass CONN_MGR_IF_NO_TIMEOUT to disable the timeout.
* @retval 0 on success.
* @retval -ENOTSUP if the provided iface is not bound to a connectivity implementation.
*/
int conn_mgr_if_set_timeout(struct net_if *iface, int timeout);
/**
* @brief Initialize all connectivity implementation bindings
*
*
*/
void conn_mgr_conn_init(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_H_ */