net: app: Create support for network application API

The network application API is a higher level API for creating
client and server type applications. Instead of applications
dealing with low level details, the network application API
provides services that most of the applications can use directly.

This commit removes the internal net_sample_*() API and converts
the existing users of it to use the new net_app API.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2017-05-10 22:23:29 +03:00 committed by Anas Nashif
commit a1be6a8ba9
19 changed files with 3566 additions and 190 deletions

897
include/net/net_app.h Normal file
View file

@ -0,0 +1,897 @@
/** @file
* @brief Common routines needed in various network applications.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __NET_APP_H
#define __NET_APP_H
#if defined(CONFIG_NET_APP_TLS)
#if defined(CONFIG_MBEDTLS)
#if !defined(CONFIG_MBEDTLS_CFG_FILE)
#include "mbedtls/config.h"
#else
#include CONFIG_MBEDTLS_CFG_FILE
#endif /* CONFIG_MBEDTLS_CFG_FILE */
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_time_t time_t
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
#endif /* MBEDTLS_PLATFORM_C */
#include <mbedtls/ssl_cookie.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/ssl.h>
#include <mbedtls/error.h>
#include <mbedtls/debug.h>
#endif /* CONFIG_MBEDTLS */
#endif /* CONFIG_NET_APP_TLS */
#include <net/net_ip.h>
#include <net/net_pkt.h>
#include <net/net_context.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Flags that tell what kind of functionality is needed by the application. */
#define NET_APP_NEED_ROUTER 0x00000001
#define NET_APP_NEED_IPV6 0x00000002
#define NET_APP_NEED_IPV4 0x00000004
enum net_app_type {
NET_APP_UNSPEC = 0,
NET_APP_SERVER,
NET_APP_CLIENT,
};
struct net_app_ctx;
/**
* @typedef net_app_recv_cb_t
* @brief Network data receive callback.
*
* @details The recv callback is called after a network data is
* received.
*
* @param ctx The context to use.
* @param pkt Network buffer that is received. If the pkt is not NULL,
* then the callback will own the buffer and it needs to to unref the pkt
* as soon as it has finished working with it. On EOF, pkt will be NULL.
* @param status Value is set to 0 if some data or the connection is
* at EOF, <0 if there was an error receiving data, in this case the
* pkt parameter is set to NULL.
* @param user_data The user data given in init call.
*/
typedef void (*net_app_recv_cb_t)(struct net_app_ctx *ctx,
struct net_pkt *pkt,
int status,
void *user_data);
/**
* @typedef net_app_connect_cb_t
* @brief Connection callback.
*
* @details The connect callback is called after a connection is being
* established.
*
* @param ctx The context to use.
* @param status Status of the connection establishment. This is 0
* if the connection was established successfully, <0 if there was an
* error.
* @param user_data The user data given in init call.
*/
typedef void (*net_app_connect_cb_t)(struct net_app_ctx *ctx,
int status,
void *user_data);
/**
* @typedef net_app_send_cb_t
* @brief Network data send callback.
*
* @details The send callback is called after a network data is
* sent.
*
* @param ctx The context to use.
* @param status Value is set to 0 if all data was sent ok, <0 if
* there was an error sending data. >0 amount of data that was
* sent when not all data was sent ok.
* @param user_data_send The user data given in net_app_send() call.
* @param user_data The user data given in init call.
*/
typedef void (*net_app_send_cb_t)(struct net_app_ctx *ctx,
int status,
void *user_data_send,
void *user_data);
/**
* @typedef net_app_close_cb_t
* @brief Close callback.
*
* @details The close callback is called after a connection is being
* shutdown.
*
* @param ctx The context to use.
* @param status Error code for the closing.
* @param user_data The user data given in init call.
*/
typedef void (*net_app_close_cb_t)(struct net_app_ctx *ctx,
int status,
void *user_data);
/** Network application callbacks */
struct net_app_cb {
/** Function that is called when a connection is established.
*/
net_app_connect_cb_t connect;
/** Function that is called when data is received from network.
*/
net_app_recv_cb_t recv;
/** Function that is called when net_pkt is sent.
*/
net_app_send_cb_t send;
/** Function that is called when connection is shutdown.
*/
net_app_close_cb_t close;
};
/* This is the same prototype as what net_context_sendto() has
* so that we can override the sending of the data for TLS traffic.
*/
typedef int (*net_app_send_data_t)(struct net_pkt *pkt,
const struct sockaddr *dst_addr,
socklen_t addrlen,
net_context_send_cb_t cb,
s32_t timeout,
void *token,
void *user_data);
#if defined(CONFIG_NET_APP_TLS)
/* Internal information for managing TLS data */
struct tls_context {
struct net_pkt *rx_pkt;
struct net_buf *frag;
struct k_sem tx_sem;
struct k_fifo tx_rx_fifo;
int remaining;
};
/* This struct is used to pass data to TLS thread when reading or sending
* data.
*/
struct net_app_fifo_block {
struct k_mem_block block;
struct net_pkt *pkt;
void *token; /* Used when sending data */
net_context_send_cb_t cb;
u8_t dir;
};
#define NET_APP_TLS_POOL_DEFINE(name, count) \
K_MEM_POOL_DEFINE(name, sizeof(struct net_app_fifo_block), \
sizeof(struct net_app_fifo_block), count, sizeof(int))
#if defined(CONFIG_NET_APP_SERVER)
/**
* @typedef net_app_cert_cb_t
* @brief Callback used when the API user needs to setup the certs.
*
* @param ctx Net app context.
* @param cert MBEDTLS certificate
* @param pkey MBEDTLS private key
*
* @return 0 if ok, <0 if there is an error
*/
typedef int (*net_app_cert_cb_t)(struct net_app_ctx *ctx,
mbedtls_x509_crt *cert,
mbedtls_pk_context *pkey);
#endif /* CONFIG_NET_APP_SERVER */
#if defined(CONFIG_NET_APP_CLIENT)
/**
* @typedef net_app_ca_cert_cb_t
* @brief Callback used when the API user needs to setup certs.
*
* @param ctx Net app client context.
* @param ca_cert MBEDTLS certificate. This is of type mbedtls_x509_crt
* if MBEDTLS_X509_CRT_PARSE_C is defined.
*
* @return 0 if ok, <0 if there is an error
*/
typedef int (*net_app_ca_cert_cb_t)(struct net_app_ctx *ctx,
void *ca_cert);
#endif /* CONFIG_NET_APP_CLIENT */
/**
* @typedef net_app_entropy_src_cb_t
* @brief Callback used when the API user needs to setup the entropy source.
* @details This is the same as mbedtls_entropy_f_source_ptr callback.
*
* @param data Callback-specific data pointer
* @param output Data to fill
* @param len Maximum size to provide
* @param olen The actual amount of bytes put into the buffer (Can be 0)
*/
typedef int (*net_app_entropy_src_cb_t)(void *data, unsigned char *output,
size_t len, size_t *olen);
#endif /* CONFIG_NET_APP_TLS */
/** Network application context. */
struct net_app_ctx {
#if defined(CONFIG_NET_IPV6)
/** Network IPv6 context. */
struct net_context *ipv6_ctx;
#endif
#if defined(CONFIG_NET_IPV4)
/** Network IPv4 context. */
struct net_context *ipv4_ctx;
#endif
/** Internal function that is called when user data is sent to
* network. By default this is set to net_context_sendto() but
* is overridden for TLS as it requires special handling.
*/
net_app_send_data_t send_data;
/** Connection callbacks */
struct net_app_cb cb;
/** Internal function that is called when data is received from
* network. This will do what ever needed and then pass data to
* application.
*/
net_context_recv_cb_t recv_cb;
/** Local address */
struct sockaddr local;
/** Remote address */
struct sockaddr remote;
#if defined(CONFIG_NET_APP_SERVER)
struct {
#if defined(CONFIG_NET_TCP)
/** Currently active network context. This will contain the
* new context that is created after connection is accepted
* when TCP is enabled.
*/
struct net_context *net_ctx;
#endif
} server;
#endif /* CONFIG_NET_APP_SERVER */
#if defined(CONFIG_NET_APP_CLIENT)
struct {
/** Connect waiter */
struct k_sem connect_wait;
#if defined(CONFIG_DNS_RESOLVER)
/** DNS resolver waiter */
struct k_sem dns_wait;
/** DNS query id. This is needed if the query needs to be
* cancelled.
*/
u16_t dns_id;
#endif
} client;
#endif /* CONFIG_NET_APP_CLIENT */
#if defined(CONFIG_NET_APP_TLS)
struct {
/** TLS stack for mbedtls library. */
u8_t *stack;
/** TLS stack size. */
int stack_size;
/** TLS thread id */
k_tid_t tid;
/** TLS thread */
struct k_thread thread;
/** Memory pool for RX data */
struct k_mem_pool *pool;
/** Where the encrypted request is stored, this is to be
* provided by the user.
*/
u8_t *request_buf;
/** Hostname to be used in the certificate verification */
const char *cert_host;
/** Request buffer maximum length */
size_t request_buf_len;
/** mbedtls related configuration. */
struct {
#if defined(CONFIG_NET_APP_SERVER)
net_app_cert_cb_t cert_cb;
mbedtls_x509_crt srvcert;
mbedtls_pk_context pkey;
#endif
#if defined(CONFIG_NET_APP_CLIENT)
net_app_ca_cert_cb_t ca_cert_cb;
mbedtls_x509_crt ca_cert;
#endif
struct tls_context ssl_ctx;
net_app_entropy_src_cb_t entropy_src_cb;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
u8_t *personalization_data;
size_t personalization_data_len;
} mbedtls;
/** Have we called connect cb yet? */
bool connect_cb_called;
} tls;
#endif /* CONFIG_NET_APP_TLS */
#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
/** Network packet (net_pkt) memory pool for network contexts attached
* to this network app context.
*/
net_pkt_get_slab_func_t tx_slab;
/** Network data net_buf pool for network contexts attached to this
* network app context.
*/
net_pkt_get_pool_func_t data_pool;
#endif
/** User data pointer */
void *user_data;
/** Type of the connection (stream or datagram) */
enum net_sock_type sock_type;
/** IP protocol type (UDP or TCP) */
enum net_ip_protocol proto;
/** Application type (client or server) of this instance */
enum net_app_type app_type;
/** Is this context setup or not */
u8_t is_init : 1;
/** Is this instance supporting TLS or not.
*/
u8_t is_tls : 1;
/** Running status of the server. If true, then the server is enabled.
* If false then it is disabled and will not serve clients.
* The server is disabled by default after initialization and will need
* to be enabled manually.
*/
u8_t is_enabled : 1;
/** Unused bits */
u8_t _padding : 5;
};
/**
* @brief Initialize this network application.
*
* @param app_info String describing this application.
* @param flags Flags related to this application startup.
* @param timeout How long to wait the network setup before continuing
* the startup.
*
* @return 0 if ok, <0 if error.
*/
int net_app_init(const char *app_info, u32_t flags, s32_t timeout);
#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
/**
* @brief Configure the net_pkt pool for this context.
*
* @details Use of this function is optional and if the pools are not set,
* then the default TX and DATA pools are used.
*
* @param tx_slab Function which is used when allocating TX network packet.
* This can be NULL in which case default TX memory pool is used.
* @param data_pool Function which is used when allocating data network buffer.
* This can be NULL in which case default DATA net_buf pool is used.
*/
int net_app_set_net_pkt_pool(struct net_app_ctx *ctx,
net_pkt_get_slab_func_t tx_slab,
net_pkt_get_pool_func_t data_pool);
#else
#define net_app_set_net_pkt_pool(...)
#endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */
#if defined(CONFIG_NET_APP_SERVER)
/**
* @brief Create a network server application.
*
* @details Note that caller must create the context and initialize it to 0
* before calling this function. The context must be valid for the whole
* duration of the application life cycle. This usually means that it
* cannot be allocated from stack.
*
* @param ctx Network application context.
* @param sock_type Connection type (stream or datagram).
* @param proto IP protocol (UDP or TCP)
* @param server_addr Local address of the server. If set to NULL, then the
* API will figure out a proper address where to bind the context.
* @param port UDP or TCP port number where the service is located. This is
* only used if server_addr parameter is NULL.
* @param timeout Timeout for this function call. This timeout tells how
* long to wait while accepting the data from network.
* @param user_data User specific data.
*
* @return 0 if ok, <0 if error.
*/
int net_app_init_server(struct net_app_ctx *ctx,
enum net_sock_type sock_type,
enum net_ip_protocol proto,
struct sockaddr *server_addr,
u16_t port,
void *user_data);
/**
* @brief Create a TCP server application.
*
* @details Note that caller must create the context and initialize it to 0
* before calling this function. The context must be valid for the whole
* duration of the application life cycle. This usually means that it
* cannot be allocated from stack.
*
* @param ctx Network application context.
* @param server_addr Local address of the server. If set to NULL, then the
* API will figure out a proper address where to bind the context.
* @param port UDP or TCP port number where the service is located. This is
* only used if server_addr parameter is NULL.
* @param timeout Timeout for this function call. This timeout tells how
* long to wait while accepting the data from network.
* @param user_data User specific data.
*
* @return 0 if ok, <0 if error.
*/
static inline int net_app_init_tcp_server(struct net_app_ctx *ctx,
struct sockaddr *server_addr,
u16_t port,
void *user_data)
{
return net_app_init_server(ctx,
SOCK_STREAM,
IPPROTO_TCP,
server_addr,
port,
user_data);
}
/**
* @brief Create a UDP server application.
*
* @details Note that caller must create the context and initialize it to 0
* before calling this function. The context must be valid for the whole
* duration of the application life cycle. This usually means that it
* cannot be allocated from stack.
*
* @param ctx Network application context.
* @param server_addr Local address of the server. If set to NULL, then the
* API will figure out a proper address where to bind the context.
* @param port UDP or TCP port number where the service is located. This is
* only used if server_addr parameter is NULL.
* @param timeout Timeout for this function call. This timeout tells how
* long to wait while accepting the data from network.
* @param user_data User specific data.
*
* @return 0 if ok, <0 if error.
*/
static inline int net_app_init_udp_server(struct net_app_ctx *ctx,
struct sockaddr *server_addr,
u16_t port,
void *user_data)
{
return net_app_init_server(ctx,
SOCK_DGRAM,
IPPROTO_UDP,
server_addr,
port,
user_data);
}
/**
* @brief Wait for an incoming connection.
*
* @details Note that caller must have called net_app_init_server() before
* calling this function. This functionality is separated from init function
* so that user can setup the callbacks after calling init. Only after calling
* this function the server starts to listen connection attempts. This function
* will not block but will initialize the local end point address so that
* receive callback will be called for incoming connection.
*
* @param ctx Network application context.
*
* @return 0 if ok, <0 if error.
*/
int net_app_listen(struct net_app_ctx *ctx);
#endif /* CONFIG_NET_APP_SERVER */
#if defined(CONFIG_NET_APP_CLIENT)
/**
* @brief Create a network client application.
*
* @details Note that caller must create the context and initialize it to 0
* before calling this function. The context must be valid for the whole
* duration of the application life cycle. This usually means that it
* cannot be allocated from stack.
*
* @param ctx Network application context.
* @param sock_type Connection type (stream or datagram).
* @param proto IP protocol (UDP or TCP)
* @param client_addr Local address of the client. If set to NULL, then the
* API will figure out a proper address where to bind the context.
* @param peer_addr Peer (target) address. If this is NULL, then the
* peer_add_str string and peer_port are used when connecting to peer.
* @param peer_addr_str Peer (target) address as a string. If this is NULL,
* then the peer_addr sockaddr is used to set the peer address. If DNS is
* configured in the system, then the hostname is automatically resolved if
* given here. Note that the port number is optional in the string. If the
* port number is not given in the string, then peer_port variable is used
* instead.
* Following syntex is supported for the address:
* 192.0.2.1
* 192.0.2.1:5353
* 2001:db8::1
* [2001:db8::1]:5353
* peer.example.com
* peer.example.com:1234
* @param peer_port Port number where to connect to. Ignored if port number is
* found in the peer_addr_str.
* @param timeout Timeout for this function call. This is used if the API
* needs to do some time consuming operation, like resolving DNS address.
* @param user_data User specific data.
*
* @return 0 if ok, <0 if error.
*/
int net_app_init_client(struct net_app_ctx *ctx,
enum net_sock_type sock_type,
enum net_ip_protocol proto,
struct sockaddr *client_addr,
struct sockaddr *peer_addr,
const char *peer_addr_str,
u16_t peer_port,
s32_t timeout,
void *user_data);
/**
* @brief Create a TCP client application.
*
* @details Note that caller must create the context and initialize it to 0
* before calling this function. The context must be valid for the whole
* duration of the application life cycle. This usually means that it
* cannot be allocated from stack.
*
* @param ctx Network application context.
* @param client_addr Local address of the client. If set to NULL, then the
* API will figure out a proper address where to bind the context.
* @param peer_addr Peer (target) address. If this is NULL, then the
* peer_add_str string and peer_port are used when connecting to peer.
* @param peer_addr_str Peer (target) address as a string. If this is NULL,
* then the peer_addr sockaddr is used to set the peer address. If DNS is
* configured in the system, then the hostname is automatically resolved if
* given here. Note that the port number is optional in the string. If the
* port number is not given in the string, then peer_port variable is used
* instead.
* Following syntex is supported for the address:
* 192.0.2.1
* 192.0.2.1:5353
* 2001:db8::1
* [2001:db8::1]:5353
* peer.example.com
* peer.example.com:1234
* @param peer_port Port number where to connect to. Ignored if port number is
* found in the peer_addr_str.
* @param timeout Timeout for this function call. This is used if the API
* needs to do some time consuming operation, like resolving DNS address.
* @param user_data User specific data.
*
* @return 0 if ok, <0 if error.
*/
static inline int net_app_init_tcp_client(struct net_app_ctx *ctx,
struct sockaddr *client_addr,
struct sockaddr *peer_addr,
const char *peer_addr_str,
u16_t peer_port,
s32_t timeout,
void *user_data)
{
return net_app_init_client(ctx,
SOCK_STREAM,
IPPROTO_TCP,
client_addr,
peer_addr,
peer_addr_str,
peer_port,
timeout,
user_data);
}
/**
* @brief Create a UDP client application.
*
* @details Note that caller must create the context and initialize it to 0
* before calling this function. The context must be valid for the whole
* duration of the application life cycle. This usually means that it
* cannot be allocated from stack.
*
* @param ctx Network application context.
* @param client_addr Local address of the client. If set to NULL, then the
* API will figure out a proper address where to bind the context.
* @param peer_addr Peer (target) address. If this is NULL, then the
* peer_add_str string and peer_port are used when connecting to peer.
* @param peer_addr_str Peer (target) address as a string. If this is NULL,
* then the peer_addr sockaddr is used to set the peer address. If DNS is
* configured in the system, then the hostname is automatically resolved if
* given here. Note that the port number is optional in the string. If the
* port number is not given in the string, then peer_port variable is used
* instead.
* Following syntex is supported for the address:
* 192.0.2.1
* 192.0.2.1:5353
* 2001:db8::1
* [2001:db8::1]:5353
* peer.example.com
* peer.example.com:1234
* @param peer_port Port number where to connect to. Ignored if port number is
* found in the peer_addr_str.
* @param timeout Timeout for this function call. This is used if the API
* needs to do some time consuming operation, like resolving DNS address.
* @param user_data User specific data.
*
* @return 0 if ok, <0 if error.
*/
static inline int net_app_init_udp_client(struct net_app_ctx *ctx,
struct sockaddr *client_addr,
struct sockaddr *peer_addr,
const char *peer_addr_str,
u16_t peer_port,
s32_t timeout,
void *user_data)
{
return net_app_init_client(ctx,
SOCK_DGRAM,
IPPROTO_UDP,
client_addr,
peer_addr,
peer_addr_str,
peer_port,
timeout,
user_data);
}
/**
* @brief Establish a network connection to peer.
*
* @param ctx Network application context.
* @param timeout How long to wait the network connection before giving up.
*
* @return 0 if ok, <0 if error.
*/
int net_app_connect(struct net_app_ctx *ctx, s32_t timeout);
#endif /* CONFIG_NET_APP_CLIENT */
/**
* @brief Set various network application callbacks.
*
* @param ctx Network app context.
* @param connect_cb Connect callback.
* @param recv_cb Data receive callback.
* @param send_cb Data sent callback.
* @param close_cb Close callback.
*
* @return 0 if ok, <0 if error.
*/
int net_app_set_cb(struct net_app_ctx *ctx,
net_app_connect_cb_t connect_cb,
net_app_recv_cb_t recv_cb,
net_app_send_cb_t send_cb,
net_app_close_cb_t close_cb);
/**
* @brief Send data that is found in net_pkt to peer.
*
* @details If the function return < 0, then it is caller responsibility
* to unref the pkt. If the packet was sent successfully, then the lower
* IP stack will release the network pkt.
*
* @param ctx Network application context.
* @param pkt Network packet to send.
* @param dst Destination address where to send packet. This is
* ignored for TCP data.
* @param dst_len Destination address structure size
* @param timeout How long to wait the send before giving up.
* @param user_data_send User data specific to this send call.
*
* @return 0 if ok, <0 if error.
*/
int net_app_send_pkt(struct net_app_ctx *ctx,
struct net_pkt *pkt,
const struct sockaddr *dst,
socklen_t dst_len,
s32_t timeout,
void *user_data_send);
/**
* @brief Send data that is found in user specified buffer to peer.
*
* @param ctx Network application context.
* @param buf Buffer to send.
* @param buf_len Amount of data to send.
* @param dst Destination address where to send packet. This is
* ignored for TCP data.
* @param dst_len Destination address structure size
* @param timeout How long to wait the send before giving up.
* @param user_data_send User data specific to this send call.
*
* @return 0 if ok, <0 if error.
*/
int net_app_send_buf(struct net_app_ctx *ctx,
u8_t *buf,
size_t buf_len,
const struct sockaddr *dst,
socklen_t dst_len,
s32_t timeout,
void *user_data_send);
/**
* @brief Create network packet.
*
* @param ctx Network application context.
* @param timeout How long to wait the send before giving up.
*
* @return valid net_pkt if ok, NULL if error.
*/
struct net_pkt *net_app_get_net_pkt(struct net_app_ctx *ctx,
s32_t timeout);
/**
* @brief Create network buffer that will hold network data.
*
* @details The returned net_buf is automatically appended to the
* end of network packet fragment chain.
*
* @param ctx Network application context.
* @param pkt Network packet to where the data buf is appended.
* @param timeout How long to wait the send before giving up.
*
* @return valid net_pkt if ok, NULL if error.
*/
struct net_buf *net_app_get_net_buf(struct net_app_ctx *ctx,
struct net_pkt *pkt,
s32_t timeout);
/**
* @brief Close a network connection to peer.
*
* @param ctx Network application context.
*
* @return 0 if ok, <0 if error.
*/
int net_app_close(struct net_app_ctx *ctx);
/**
* @brief Release this network application context.
*
* @details No network data will be received via this context after this
* call.
*
* @param ctx Network application context.
*
* @return 0 if ok, <0 if error.
*/
int net_app_release(struct net_app_ctx *ctx);
#if defined(CONFIG_NET_APP_TLS)
#if defined(CONFIG_NET_APP_CLIENT)
/**
* @brief Initialize TLS support for this net_app client context.
*
* @param ctx net_app context.
* @param request_buf Caller supplied buffer where the TLS request will be
* stored
* @param request_buf_len Length of the caller suppied buffer.
* @param personalization_data Personalization data (Device specific
* identifiers) for random number generator. (Can be NULL).
* @param personalization_data_len Length of the personalization data.
* @param cert_cb User supplied callback that setups the certifacates.
* @param cert_host Hostname that is used to verify the server certificate.
* This value is used when net_api API calls mbedtls_ssl_set_hostname()
* which sets the hostname to check against the received server certificate.
* See https://tls.mbed.org/kb/how-to/use-sni for more details.
* This can be left NULL in which case mbedtls will silently skip certificate
* verification entirely. This option is only used if MBEDTLS_X509_CRT_PARSE_C
* is enabled in mbedtls config file.
* @param entropy_src_cb User supplied callback that setup the entropy. This
* can be set to NULL, in which case default entropy source is used.
* @param pool Memory pool for RX data reads.
* @param stack TLS thread stack.
* @param stack_len TLS thread stack size.
*
* @return Return 0 if ok, <0 if error.
*/
int net_app_client_tls(struct net_app_ctx *ctx,
u8_t *request_buf,
size_t request_buf_len,
u8_t *personalization_data,
size_t personalization_data_len,
net_app_ca_cert_cb_t cert_cb,
const char *cert_host,
net_app_entropy_src_cb_t entropy_src_cb,
struct k_mem_pool *pool,
u8_t *stack,
size_t stack_size);
#endif /* CONFIG_NET_APP_CLIENT */
#if defined(CONFIG_NET_APP_SERVER)
/**
* @brief Initialize TLS support for this net_app server context.
*
* @param ctx net_app context.
* @param request_buf Caller supplied buffer where the TLS request will be
* stored
* @param request_buf_len Length of the caller suppied buffer.
* @param server_banner Print information about started service. This is only
* printed if net_app debugging is activated. The parameter can be set to NULL
* if no extra prints are needed.
* @param personalization_data Personalization data (Device specific
* identifiers) for random number generator. (Can be NULL).
* @param personalization_data_len Length of the personalization data.
* @param cert_cb User supplied callback that setups the certifacates.
* @param entropy_src_cb User supplied callback that setup the entropy. This
* can be set to NULL, in which case default entropy source is used.
* @param pool Memory pool for RX data reads.
* @param stack TLS thread stack.
* @param stack_len TLS thread stack size.
*
* @return Return 0 if ok, <0 if error.
*/
int net_app_server_tls(struct net_app_ctx *ctx,
u8_t *request_buf,
size_t request_buf_len,
const char *server_banner,
u8_t *personalization_data,
size_t personalization_data_len,
net_app_cert_cb_t cert_cb,
net_app_entropy_src_cb_t entropy_src_cb,
struct k_mem_pool *pool,
u8_t *stack,
size_t stack_len);
bool net_app_server_tls_enable(struct net_app_ctx *ctx);
bool net_app_server_tls_disable(struct net_app_ctx *ctx);
#endif /* CONFIG_NET_APP_SERVER */
#endif /* CONFIG_NET_APP_SEC */
#ifdef __cplusplus
}
#endif
#endif /* __NET_APP_H */

View file

@ -13,9 +13,25 @@ endif
ifeq ($(CONFIG_NET_L2_IEEE802154), y)
ifeq ($(CONFIG_NET_APP_SETTINGS), y)
ccflags-y += -I${ZEPHYR_BASE}/samples/net/common/
obj-y += ../../common/ieee802154_settings.o
endif
endif
ccflags-y += -I${ZEPHYR_BASE}/samples/net/common/
obj-y += ../../common/sample_app_setup.o
ifeq ($(CONFIG_IEEE802154_CC2520),y)
ifeq ($(CONFIG_BOARD_ARDUINO_101),y)
ccflags-y +=-I${ZEPHYR_BASE}/include/drivers/
obj-y += ../../common/cc2520_a101.o
endif
ifeq ($(CONFIG_BOARD_FRDM_K64F),y)
ccflags-y +=-I${ZEPHYR_BASE}/drivers/
ccflags-y +=-I${ZEPHYR_BASE}/include/drivers/
obj-y += ../../common/cc2520_frdm_k64f.o
endif
endif
ifeq ($(CONFIG_NET_TESTING), y)
ccflags-y +=-I${ZEPHYR_BASE}/samples/net/common/
ccflags-y +=-DNET_TESTING_SERVER=1
endif

View file

@ -1,29 +0,0 @@
/** @file
* @brief Common routines needed in various network sample applications.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __NET_SAMPLE_APP_H
#define __NET_SAMPLE_APP_H
#ifdef __cplusplus
extern "C" {
#endif
/* What kind of functionality is needed by the application. */
#define NET_SAMPLE_NEED_ROUTER 0x00000001
#define NET_SAMPLE_NEED_IPV6 0x00000002
#define NET_SAMPLE_NEED_IPV4 0x00000004
int net_sample_app_init(const char *app_info, u32_t flags, s32_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* __NET_SAMPLE_APP_H */

View file

@ -18,7 +18,7 @@
#include <net/http.h>
#include <net_sample_app.h>
#include <net/net_app.h>
#include "config.h"
@ -307,7 +307,7 @@ void main(void)
{
int ret;
ret = net_sample_app_init("Run HTTP client", 0, APP_STARTUP_TIME);
ret = net_app_init("Run HTTP client", 0, APP_STARTUP_TIME);
if (ret < 0) {
panic("Application init failed");
}

View file

@ -25,7 +25,7 @@
#include <net/net_context.h>
#include <net/http.h>
#include <net_sample_app.h>
#include <net/net_app.h>
#include "config.h"
@ -279,13 +279,13 @@ void main(void)
* before continuing.
*/
#if defined(CONFIG_NET_IPV6)
flags |= NET_SAMPLE_NEED_IPV6;
flags |= NET_APP_NEED_IPV6;
#endif
#if defined(CONFIG_NET_IPV4)
flags |= NET_SAMPLE_NEED_IPV4;
flags |= NET_APP_NEED_IPV4;
#endif
ret = net_sample_app_init(APP_BANNER, flags, APP_STARTUP_TIME);
ret = net_app_init(APP_BANNER, flags, APP_STARTUP_TIME);
if (ret < 0) {
panic("Application init failed");
}

View file

@ -4,6 +4,4 @@
# SPDX-License-Identifier: Apache-2.0
#
include $(ZEPHYR_BASE)/samples/net/common/Makefile.common
obj-y += main.o

View file

@ -18,7 +18,7 @@
#include <net/http.h>
#include <net_sample_app.h>
#include <net/net_app.h>
#include "config.h"
@ -370,7 +370,7 @@ void main(void)
bool failure = false;
int ret;
ret = net_sample_app_init("Run HTTPS client", 0, APP_STARTUP_TIME);
ret = net_app_init("Run HTTPS client", 0, APP_STARTUP_TIME);
if (ret < 0) {
panic("Application init failed");
}

View file

@ -345,6 +345,4 @@ source "subsys/net/ip/Kconfig.rpl"
source "subsys/net/ip/Kconfig.stats"
source "subsys/net/ip/Kconfig.app"
endmenu

View file

@ -1,113 +0,0 @@
# Kconfig.app - Options for sample applications
#
# Copyright (c) 2016 Intel Corporation.
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig NET_APP_SETTINGS
bool "Set network settings for sample applications"
default n
help
Allow IP addresses to be set in config file for
networking client/server sample applications, or
some link-layer dedicated settings like the channel.
Beware this is not meant to be used for proper
provisioning but quick sampling/testing.
if NET_APP_SETTINGS
if NET_IPV6
config NET_APP_MY_IPV6_ADDR
string "My IPv6 address"
help
Use 2001:db8::1 here if uncertain.
config NET_APP_PEER_IPV6_ADDR
string "Peer IPv6 address"
help
This is only applicable in client side applications that try
to establish a connection to peer host.
Use 2001:db8::2 here if uncertain.
endif # NET_IPV6
if NET_IPV4
config NET_APP_MY_IPV4_ADDR
string "My IPv4 address"
help
Use 192.0.2.1 here if uncertain.
config NET_APP_PEER_IPV4_ADDR
string "Peer IPv4 address"
help
This is only applicable in client side applications that try
to establish a connection to peer host.
Use 192.0.2.2 here if uncertain.
endif # NET_IPV4
if NET_L2_IEEE802154 || NET_L2_RAW_CHANNEL
config NET_APP_IEEE802154_DEV_NAME
string "IEEE 802.15.4 device name"
help
The device name to get bindings from in the sample application.
config NET_APP_IEEE802154_PAN_ID
hex "IEEE 802.15.4 PAN ID"
default 0xabcd
help
The PAN ID to use by default in the sample.
config NET_APP_IEEE802154_CHANNEL
int "IEEE 802.15.4 channel"
default 26
help
The channel to use by default in the sample application.
config NET_APP_IEEE802154_RADIO_TX_POWER
int "IEEE 802.15.4 TX power in dbm"
default 0
help
The TX power to use by default in the sample application.
See NET_L2_IEEE802154_RADIO_DFLT_TX_POWER for more info.
config NET_APP_IEEE802154_SECURITY_KEY
string "IEEE 802.15.4 security key"
default "moooh!"
depends on NET_L2_IEEE802154_SECURITY
help
The key string to use for the link-layer security part.
config NET_APP_IEEE802154_SECURITY_KEY_MODE
int "IEEE 802.15.4 security key mode"
default 0
range 0 0
depends on NET_L2_IEEE802154_SECURITY
help
The key mode to use for the link-layer security part.
Only implicit mode is supported, thus 0.
config NET_APP_IEEE802154_SECURITY_LEVEL
int "IEEE 802.15.4 security level (0-7)"
default 0
range 0 7
depends on NET_L2_IEEE802154_SECURITY
help
The security level to use for the link-layer security part.
0 means no security
1 authentication only with a 4 bytes length tag
2 authentication only with a 8 bytes length tag
3 authentication only with a 16 bytes length tag
4 encryption only
5 encryption/authentication with a 4 bytes length tag
6 encryption/authentication with a 8 bytes length tag
7 encryption/authentication with a 16 bytes length tag
endif # NET_L2_IEEE802154 || NET_L2_RAW_CHANNEL
endif # NET_APP_SETTINGS

View file

@ -3,3 +3,4 @@ obj-$(CONFIG_ZOAP) += zoap/
obj-$(CONFIG_DNS_RESOLVER) += dns/
obj-$(CONFIG_MQTT_LIB) += mqtt/
obj-$(CONFIG_HTTP) += http/
obj-$(CONFIG_NET_APP_SETTINGS) += app/

View file

@ -17,3 +17,9 @@ source "subsys/net/lib/mqtt/Kconfig"
source "subsys/net/lib/http/Kconfig"
endmenu
menu "Network Applications"
source "subsys/net/lib/app/Kconfig"
endmenu

View file

@ -17,3 +17,7 @@ endif
ifdef CONFIG_HTTP
include $(srctree)/subsys/net/lib/http/Makefile
endif
ifdef CONFIG_NET_APP_SETTINGS
include $(srctree)/subsys/net/lib/app/Makefile
endif

223
subsys/net/lib/app/Kconfig Normal file
View file

@ -0,0 +1,223 @@
# Kconfig.app - Options for networking applications
#
# Copyright (c) 2017 Intel Corporation.
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig NET_APP
bool "Network application API support [EXPERIMENTAL]"
default y
select NET_MGMT
select NET_MGMT_EVENT
help
Enable API that helps to create client/server network applications.
This API is experimental and subject to change.
if NET_APP
config NET_APP_AUTO_INIT
bool "Init networking support automatically during device startup"
default y
help
If this option is set, then the net_app API is automatically
initialized when the device is started. If you do not wish to do
this, then disable this and call net_app_init() in your application.
config NET_APP_INIT_PRIO
int "Startup priority for the network application init"
default 95
depends on NET_APP_AUTO_INIT
config NET_APP_INIT_TIMEOUT
int "How long to wait for networking to be ready and available"
default 30
depends on NET_APP_AUTO_INIT
help
The value is in seconds. If for example IPv4 address from DHCPv4 is not
received within this limit, then the net_app_init() call will fail
during the device startup.
config NET_APP_NEED_IPV6
bool "This application wants IPv6 support"
depends on NET_APP_AUTO_INIT
select NET_IPV6
help
The network application needs IPv6 support to function properly.
This option makes sure the network application is initialized properly
in order to use IPv6.
config NET_APP_NEED_IPV6_ROUTER
bool "This application wants IPv6 router to exists"
depends on NET_APP_AUTO_INIT
depends on NET_IPV6
help
The network application needs IPv6 router to exists before continuing.
What this means that the application wants to wait until it receives
IPv6 router advertisement message before continuing.
config NET_APP_NEED_IPV4
bool "This application wants IPv4 support"
depends on NET_APP_AUTO_INIT
select NET_IPV4
help
The network application needs IPv4 support to function properly.
This option makes sure the network application is initialized properly
in order to use IPv4.
config NET_DEBUG_APP
bool "Debug net app library"
default n
help
Enables net app library to output debug messages
config NET_APP_SERVER
bool "Enable server support"
default n
help
Enables net app library server APIs.
config NET_APP_CLIENT
bool "Enable client support"
default n
help
Enables net app library client APIs.
config NET_APP_TLS
bool "Enable TLS support for TCP applications"
default n
select MBEDTLS
help
Enables net app library to use TLS for encrypted communication.
config NET_DEBUG_APP_TLS_LEVEL
int "Debug level for mbedtls in net app library"
depends on NET_APP_TLS && NET_DEBUG_APP
default 0
range 0 4
help
Sets log level for the mbedtls when debugging net_app library.
Levels are (from ext/lib/crypto/mbedtls/include/mbedtls/debug.h):
0 No debug
1 Error
2 State change
3 Information
4 Verbose
config NET_APP_TLS_STACK_SIZE
int "TLS handler thread stack size"
default 8192
depends on NET_APP_TLS
help
TLS handler thread stack size. The mbedtls routines will use this stack
thus it is by default very large.
endif # NET_APP
menuconfig NET_APP_SETTINGS
bool "Set network settings for applications"
default n
depends on NET_APP
help
Allow IP addresses to be set in config file for
networking client/server sample applications, or
some link-layer dedicated settings like the channel.
Beware this is not meant to be used for proper
provisioning but quick sampling/testing.
if NET_APP_SETTINGS
if NET_IPV6
config NET_APP_MY_IPV6_ADDR
string "My IPv6 address"
help
Use 2001:db8::1 here if uncertain.
config NET_APP_PEER_IPV6_ADDR
string "Peer IPv6 address"
help
This is only applicable in client side applications that try
to establish a connection to peer host.
Use 2001:db8::2 here if uncertain.
endif # NET_IPV6
if NET_IPV4
config NET_APP_MY_IPV4_ADDR
string "My IPv4 address"
help
Use 192.0.2.1 here if uncertain.
config NET_APP_PEER_IPV4_ADDR
string "Peer IPv4 address"
help
This is only applicable in client side applications that try
to establish a connection to peer host.
Use 192.0.2.2 here if uncertain.
endif # NET_IPV4
if NET_L2_IEEE802154 || NET_L2_RAW_CHANNEL
config NET_APP_IEEE802154_DEV_NAME
string "IEEE 802.15.4 device name"
help
The device name to get bindings from in the sample application.
config NET_APP_IEEE802154_PAN_ID
hex "IEEE 802.15.4 PAN ID"
default 0xabcd
help
The PAN ID to use by default in the sample.
config NET_APP_IEEE802154_CHANNEL
int "IEEE 802.15.4 channel"
default 26
help
The channel to use by default in the sample application.
config NET_APP_IEEE802154_RADIO_TX_POWER
int "IEEE 802.15.4 TX power in dbm"
default 0
help
The TX power to use by default in the sample application.
See NET_L2_IEEE802154_RADIO_DFLT_TX_POWER for more info.
config NET_APP_IEEE802154_SECURITY_KEY
string "IEEE 802.15.4 security key"
default "moooh!"
depends on NET_L2_IEEE802154_SECURITY
help
The key string to use for the link-layer security part.
config NET_APP_IEEE802154_SECURITY_KEY_MODE
int "IEEE 802.15.4 security key mode"
default 0
range 0 0
depends on NET_L2_IEEE802154_SECURITY
help
The key mode to use for the link-layer security part.
Only implicit mode is supported, thus 0.
config NET_APP_IEEE802154_SECURITY_LEVEL
int "IEEE 802.15.4 security level (0-7)"
default 0
range 0 7
depends on NET_L2_IEEE802154_SECURITY
help
The security level to use for the link-layer security part.
0 means no security
1 authentication only with a 4 bytes length tag
2 authentication only with a 8 bytes length tag
3 authentication only with a 16 bytes length tag
4 encryption only
5 encryption/authentication with a 4 bytes length tag
6 encryption/authentication with a 8 bytes length tag
7 encryption/authentication with a 16 bytes length tag
endif # NET_L2_IEEE802154 || NET_L2_RAW_CHANNEL
endif # NET_APP_SETTINGS

View file

@ -0,0 +1,20 @@
#
# Copyright (c) 2017 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
ccflags-$(CONFIG_NET_L2_BLUETOOTH) += -I${ZEPHYR_BASE}/samples/bluetooth/
ccflags-$(CONFIG_NET_L2_IEEE802154) += -I${ZEPHYR_BASE}/samples/net/common/
obj-$(CONFIG_NET_APP) += init.o
obj-$(CONFIG_NET_APP_SERVER) += server.o
obj-$(CONFIG_NET_APP_CLIENT) += client.o
ifeq ($(CONFIG_NET_APP_SERVER),y)
obj-y += net_app.o
else
ifeq ($(CONFIG_NET_APP_CLIENT),y)
obj-y += net_app.o
endif
endif

602
subsys/net/lib/app/client.c Normal file
View file

@ -0,0 +1,602 @@
/* client.c */
/*
* Copyright (c) 2017 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#if defined(CONFIG_NET_DEBUG_APP)
#define SYS_LOG_DOMAIN "net/app"
#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
#define NET_LOG_ENABLED 1
#endif
#include <zephyr.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <net/net_core.h>
#include <net/net_ip.h>
#include <net/net_if.h>
#include <net/dns_resolve.h>
#include <net/net_app.h>
#include "net_app_private.h"
#if defined(CONFIG_NET_APP_TLS)
#define TLS_STARTUP_TIMEOUT K_SECONDS(5)
static int start_tls_client(struct net_app_ctx *ctx);
#endif /* CONFIG_NET_APP_TLS */
#if defined(CONFIG_DNS_RESOLVER)
static void dns_cb(enum dns_resolve_status status,
struct dns_addrinfo *info,
void *user_data)
{
struct net_app_ctx *ctx = user_data;
if (!(status == DNS_EAI_INPROGRESS && info)) {
return;
}
if (info->ai_family == AF_INET) {
#if defined(CONFIG_NET_IPV4)
net_ipaddr_copy(&net_sin(&ctx->remote)->sin_addr,
&net_sin(&info->ai_addr)->sin_addr);
#else
goto out;
#endif
} else if (info->ai_family == AF_INET6) {
#if defined(CONFIG_NET_IPV6)
net_ipaddr_copy(&net_sin6(&ctx->remote)->sin6_addr,
&net_sin6(&info->ai_addr)->sin6_addr);
#else
goto out;
#endif
} else {
goto out;
}
ctx->remote.family = info->ai_family;
out:
k_sem_give(&ctx->client.dns_wait);
}
static int resolve_name(struct net_app_ctx *ctx,
const char *peer_addr_str,
enum dns_query_type type,
s32_t timeout)
{
int ret;
k_sem_init(&ctx->client.dns_wait, 0, 1);
ret = dns_get_addr_info(peer_addr_str, type, &ctx->client.dns_id,
dns_cb, ctx, timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)", peer_addr_str, ret);
ctx->client.dns_id = 0;
return ret;
}
/* Wait a little longer for the DNS to finish so that
* the DNS will timeout before the semaphore.
*/
if (k_sem_take(&ctx->client.dns_wait, timeout + K_SECONDS(1))) {
NET_ERR("Timeout while resolving %s", peer_addr_str);
ctx->client.dns_id = 0;
return -ETIMEDOUT;
}
ctx->client.dns_id = 0;
if (ctx->remote.family == AF_UNSPEC) {
return -EINVAL;
}
return 0;
}
#endif /* CONFIG_DNS_RESOLVER */
static int get_port_number(const char *peer_addr_str,
char *buf,
size_t buf_len)
{
u16_t port = 0;
char *ptr;
int count, i;
if (peer_addr_str[0] == '[') {
#if defined(CONFIG_NET_IPV6)
/* IPv6 address with port number */
int end;
ptr = strstr(peer_addr_str, "]:");
if (!ptr) {
return -EINVAL;
}
end = min(INET6_ADDRSTRLEN, ptr - (peer_addr_str + 1));
memcpy(buf, peer_addr_str + 1, end);
buf[end] = '\0';
port = strtol(ptr + 2, NULL, 10);
return port;
#else
return -EAFNOSUPPORT;
#endif /* CONFIG_NET_IPV6 */
}
count = i = 0;
while (peer_addr_str[i]) {
if (peer_addr_str[i] == ':') {
count++;
}
i++;
}
if (count == 1) {
#if defined(CONFIG_NET_IPV4)
/* IPv4 address with port number */
int end;
ptr = strstr(peer_addr_str, ":");
if (!ptr) {
return -EINVAL;
}
end = min(NET_IPV4_ADDR_LEN, ptr - peer_addr_str);
memcpy(buf, peer_addr_str, end);
buf[end] = '\0';
port = strtol(ptr + 1, NULL, 10);
return port;
#else
return -EAFNOSUPPORT;
#endif /* CONFIG_NET_IPV4 */
}
return 0;
}
static int set_remote_addr(struct net_app_ctx *ctx,
const char *peer_addr_str,
u16_t peer_port,
s32_t timeout)
{
char addr_str[INET6_ADDRSTRLEN + 1];
char *addr;
int ret;
/* If the peer string contains port number, use that and ignore
* the port number parameter.
*/
ret = get_port_number(peer_addr_str, addr_str, sizeof(addr_str));
if (ret > 0) {
addr = addr_str;
peer_port = ret;
} else {
addr = (char *)peer_addr_str;
}
#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
ret = net_addr_pton(AF_INET6, addr,
&net_sin6(&ctx->remote)->sin6_addr);
if (ret < 0) {
/* Could be hostname, try DNS if configured. */
#if !defined(CONFIG_DNS_RESOLVER)
NET_ERR("Invalid IPv6 address %s", addr);
return -EINVAL;
#else
ret = resolve_name(ctx, addr, DNS_QUERY_TYPE_AAAA, timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)", addr, ret);
return ret;
}
#endif
}
net_sin6(&ctx->remote)->sin6_port = htons(peer_port);
net_sin6(&ctx->remote)->sin6_family = AF_INET6;
#endif /* IPV6 && !IPV4 */
#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
ret = net_addr_pton(AF_INET, addr,
&net_sin(&ctx->remote)->sin_addr);
if (ret < 0) {
/* Could be hostname, try DNS if configured. */
#if !defined(CONFIG_DNS_RESOLVER)
NET_ERR("Invalid IPv4 address %s", addr);
return -EINVAL;
#else
ret = resolve_name(ctx, addr, DNS_QUERY_TYPE_A, timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)", addr, ret);
return ret;
}
#endif
}
net_sin(&ctx->remote)->sin_port = htons(peer_port);
net_sin(&ctx->remote)->sin_family = AF_INET;
#endif /* IPV6 && !IPV4 */
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
ret = net_addr_pton(AF_INET, addr,
&net_sin(&ctx->remote)->sin_addr);
if (ret < 0) {
ret = net_addr_pton(AF_INET6, addr,
&net_sin6(&ctx->remote)->sin6_addr);
if (ret < 0) {
/* Could be hostname, try DNS if configured. */
#if !defined(CONFIG_DNS_RESOLVER)
NET_ERR("Invalid IPv4 or IPv6 address %s", addr);
return -EINVAL;
#else
ret = resolve_name(ctx, addr,
DNS_QUERY_TYPE_A, timeout);
if (ret < 0) {
ret = resolve_name(ctx, addr,
DNS_QUERY_TYPE_AAAA,
timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)",
addr, ret);
return ret;
}
goto ipv6;
}
goto ipv4;
#endif /* !CONFIG_DNS_RESOLVER */
} else {
#if defined(CONFIG_DNS_RESOLVER)
ipv6:
#endif
net_sin6(&ctx->remote)->sin6_port =
htons(peer_port);
net_sin6(&ctx->remote)->sin6_family = AF_INET6;
}
} else {
#if defined(CONFIG_DNS_RESOLVER)
ipv4:
#endif
net_sin(&ctx->remote)->sin_port = htons(peer_port);
net_sin(&ctx->remote)->sin_family = AF_INET;
}
#endif /* IPV4 && IPV6 */
/* If we have not yet figured out what is the protocol family,
* then we cannot continue.
*/
if (ctx->remote.family == AF_UNSPEC) {
NET_ERR("Unknown protocol family.");
return -EPFNOSUPPORT;
}
return 0;
}
int net_app_init_client(struct net_app_ctx *ctx,
enum net_sock_type sock_type,
enum net_ip_protocol proto,
struct sockaddr *client_addr,
struct sockaddr *peer_addr,
const char *peer_addr_str,
u16_t peer_port,
s32_t timeout,
void *user_data)
{
struct sockaddr addr;
int ret;
if (!ctx) {
return -EINVAL;
}
if (ctx->is_init) {
return -EALREADY;
}
memset(&addr, 0, sizeof(addr));
if (client_addr) {
memcpy(&addr, client_addr, sizeof(addr));
} else {
addr.family = AF_UNSPEC;
}
ctx->app_type = NET_APP_CLIENT;
ctx->user_data = user_data;
ctx->send_data = net_context_sendto;
ctx->recv_cb = _net_app_received;
ctx->proto = proto;
ctx->sock_type = sock_type;
ret = _net_app_config_local_ctx(ctx, sock_type, proto, &addr);
if (ret < 0) {
goto fail;
}
if (peer_addr) {
memcpy(&ctx->remote, peer_addr,
sizeof(ctx->remote));
goto out;
}
if (!peer_addr_str) {
NET_ERR("Cannot know where to connect.");
ret = -EINVAL;
goto fail;
}
ret = set_remote_addr(ctx, peer_addr_str, peer_port, timeout);
if (ret < 0) {
goto fail;
}
#if defined(CONFIG_NET_IPV4)
if (ctx->remote.family == AF_INET) {
ctx->local.family = AF_INET;
_net_app_set_local_addr(&ctx->local, NULL,
net_sin(&ctx->local)->sin_port);
ret = _net_app_set_net_ctx(ctx, ctx->ipv4_ctx, &ctx->local,
sizeof(struct sockaddr_in),
ctx->proto);
if (ret < 0) {
net_context_put(ctx->ipv4_ctx);
ctx->ipv4_ctx = NULL;
}
}
#endif
#if defined(CONFIG_NET_IPV6)
if (ctx->remote.family == AF_INET6) {
ctx->local.family = AF_INET6;
_net_app_set_local_addr(&ctx->local, NULL,
net_sin6(&ctx->local)->sin6_port);
ret = _net_app_set_net_ctx(ctx, ctx->ipv6_ctx, &ctx->local,
sizeof(struct sockaddr_in6),
ctx->proto);
if (ret < 0) {
net_context_put(ctx->ipv6_ctx);
ctx->ipv6_ctx = NULL;
}
}
#endif
_net_app_print_info(ctx);
out:
ctx->is_init = true;
fail:
return ret;
}
static void _app_connected(struct net_context *net_ctx,
int status,
void *user_data)
{
struct net_app_ctx *ctx = user_data;
#if defined(CONFIG_NET_APP_TLS)
if (ctx->is_tls && ctx->proto == IPPROTO_TCP) {
k_sem_give(&ctx->client.connect_wait);
}
#endif
net_context_recv(net_ctx, ctx->recv_cb, K_NO_WAIT, ctx);
#if defined(CONFIG_NET_APP_TLS)
if (ctx->is_tls && ctx->proto == IPPROTO_TCP) {
/* If we have TLS connection, the connect cb is called
* after TLS handshakes are done.
*/
NET_DBG("Postponing TLS connection cb for ctx %p", ctx);
} else
#endif
{
if (ctx->cb.connect) {
ctx->cb.connect(ctx, status, ctx->user_data);
}
}
}
int net_app_connect(struct net_app_ctx *ctx, s32_t timeout)
{
struct net_context *net_ctx;
bool started = false;
int ret;
if (!ctx) {
return -EINVAL;
}
if (!ctx->is_init) {
return -ENOENT;
}
if (ctx->app_type != NET_APP_CLIENT) {
return -EINVAL;
}
net_ctx = _net_app_select_net_ctx(ctx);
if (!net_ctx) {
return -EAFNOSUPPORT;
}
#if defined(CONFIG_NET_APP_TLS)
if (ctx->is_tls && ctx->proto == IPPROTO_TCP && !ctx->tls.tid) {
/* TLS thread is not yet running, start it now */
ret = start_tls_client(ctx);
if (ret < 0) {
NET_DBG("TLS thread cannot be started (%d)", ret);
return ret;
}
started = true;
/* Let the TLS thread run first */
k_yield();
}
#else
ARG_UNUSED(started);
#endif /* CONFIG_NET_APP_TLS */
ret = net_context_connect(net_ctx,
&ctx->remote,
sizeof(ctx->remote),
_app_connected,
timeout,
ctx);
if (ret < 0) {
NET_DBG("Cannot connect to peer (%d)", ret);
#if defined(CONFIG_NET_APP_TLS)
if (started) {
_net_app_tls_handler_stop(ctx);
}
#endif
}
return ret;
}
#if defined(CONFIG_NET_APP_TLS)
static void tls_client_handler(struct net_app_ctx *ctx,
struct k_sem *startup_sync)
{
int ret;
NET_DBG("Starting TLS client thread for %p", ctx);
ret = _net_app_tls_init(ctx, MBEDTLS_SSL_IS_CLIENT);
if (ret < 0) {
NET_DBG("TLS client init failed");
return;
}
k_sem_give(startup_sync);
/* We wait until TLS connection is established */
k_sem_take(&ctx->client.connect_wait, K_FOREVER);
_net_app_ssl_mainloop(ctx);
mbedtls_ssl_close_notify(&ctx->tls.mbedtls.ssl);
/* If there is any pending data that have not been processed
* yet, we need to free it here.
*/
if (ctx->tls.mbedtls.ssl_ctx.rx_pkt) {
net_pkt_unref(ctx->tls.mbedtls.ssl_ctx.rx_pkt);
ctx->tls.mbedtls.ssl_ctx.rx_pkt = NULL;
ctx->tls.mbedtls.ssl_ctx.frag = NULL;
}
if (ctx->cb.close) {
ctx->cb.close(ctx, -ESHUTDOWN, ctx->user_data);
}
_net_app_tls_handler_stop(ctx);
}
static int start_tls_client(struct net_app_ctx *ctx)
{
struct k_sem startup_sync;
/* Start the thread that handles TLS traffic. */
if (ctx->tls.tid) {
return -EALREADY;
}
k_sem_init(&startup_sync, 0, 1);
ctx->tls.tid = k_thread_create(&ctx->tls.thread,
ctx->tls.stack,
ctx->tls.stack_size,
(k_thread_entry_t)tls_client_handler,
ctx, &startup_sync, 0,
K_PRIO_COOP(7), 0, 0);
/* Wait until we know that the TLS thread startup was ok */
if (k_sem_take(&startup_sync, TLS_STARTUP_TIMEOUT) < 0) {
_net_app_tls_handler_stop(ctx);
return -ECANCELED;
}
return 0;
}
int net_app_client_tls(struct net_app_ctx *ctx,
u8_t *request_buf,
size_t request_buf_len,
u8_t *personalization_data,
size_t personalization_data_len,
net_app_ca_cert_cb_t cert_cb,
const char *cert_host,
net_app_entropy_src_cb_t entropy_src_cb,
struct k_mem_pool *pool,
u8_t *stack,
size_t stack_size)
{
if (!request_buf || request_buf_len == 0) {
NET_ERR("Request buf must be set");
return -EINVAL;
}
/* mbedtls cannot receive or send larger buffer as what is defined
* in a file pointed by CONFIG_MBEDTLS_CFG_FILE.
*/
if (request_buf_len > MBEDTLS_SSL_MAX_CONTENT_LEN) {
NET_ERR("Request buf too large, max len is %d",
MBEDTLS_SSL_MAX_CONTENT_LEN);
return -EINVAL;
}
if (!cert_cb) {
NET_ERR("Cert callback must be set");
return -EINVAL;
}
ctx->is_tls = true;
ctx->send_data = _net_app_tls_sendto;
ctx->recv_cb = _net_app_tls_received;
ctx->tls.request_buf = request_buf;
ctx->tls.request_buf_len = request_buf_len;
ctx->tls.cert_host = cert_host;
ctx->tls.stack = stack;
ctx->tls.stack_size = stack_size;
ctx->tls.mbedtls.ca_cert_cb = cert_cb;
ctx->tls.pool = pool;
ctx->tls.mbedtls.personalization_data = personalization_data;
ctx->tls.mbedtls.personalization_data_len = personalization_data_len;
if (entropy_src_cb) {
ctx->tls.mbedtls.entropy_src_cb = entropy_src_cb;
} else {
ctx->tls.mbedtls.entropy_src_cb = _net_app_entropy_source;
}
/* The semaphore is released when the client calls net_app_connect() */
k_sem_init(&ctx->client.connect_wait, 0, 1);
/* The mbedtls is initialized in TLS thread because of mbedtls stack
* requirements. TLS thread is started when we get the first client
* request to send data.
*/
return 0;
}
#endif /* CONFIG_NET_APP_TLS */

View file

@ -1,4 +1,4 @@
/* sample_app_setup.c */
/* init.c */
/*
* Copyright (c) 2017 Intel Corporation.
@ -6,30 +6,26 @@
* SPDX-License-Identifier: Apache-2.0
*/
#if 1
#define SYS_LOG_DOMAIN "sample/net"
#if defined(CONFIG_NET_DEBUG_APP)
#define SYS_LOG_DOMAIN "net/app"
#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
#define NET_LOG_ENABLED 1
#endif
#include <zephyr.h>
#include <init.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <net/net_core.h>
#include <net/net_ip.h>
#include <net/net_if.h>
#include <net/dhcpv4.h>
#include <net/net_mgmt.h>
#include <net/dns_resolve.h>
#include "net_sample_app.h"
#if defined(CONFIG_NET_L2_BLUETOOTH)
#include <bluetooth/bluetooth.h>
#include <gatt/ipss.h>
#endif
#if defined(CONFIG_NET_L2_IEEE802154)
#include <ieee802154_settings.h>
#endif
#include <net/net_app.h>
static struct k_sem waiter = K_SEM_INITIALIZER(waiter, 0, 1);
static struct k_sem counter;
@ -41,7 +37,9 @@ static void ipv4_addr_add_handler(struct net_mgmt_event_callback *cb,
u32_t mgmt_event,
struct net_if *iface)
{
#if defined(CONFIG_NET_DEBUG_APP) && CONFIG_SYS_LOG_NET_LEVEL > 1
char hr_addr[NET_IPV4_ADDR_LEN];
#endif
int i;
if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) {
@ -95,7 +93,9 @@ static void setup_dhcpv4(struct net_if *iface)
static void setup_ipv4(struct net_if *iface)
{
#if defined(CONFIG_NET_DEBUG_APP) && CONFIG_SYS_LOG_NET_LEVEL > 1
char hr_addr[NET_IPV4_ADDR_LEN];
#endif
struct in_addr addr;
if (net_addr_pton(AF_INET, CONFIG_NET_APP_MY_IPV4_ADDR, &addr)) {
@ -128,7 +128,9 @@ static void ipv6_event_handler(struct net_mgmt_event_callback *cb,
u32_t mgmt_event, struct net_if *iface)
{
if (mgmt_event == NET_EVENT_IPV6_DAD_SUCCEED) {
#if defined(CONFIG_NET_DEBUG_APP) && CONFIG_SYS_LOG_NET_LEVEL > 1
char hr_addr[NET_IPV6_ADDR_LEN];
#endif
struct net_if_addr *ifaddr;
ifaddr = net_if_ipv6_addr_lookup(&laddr, &iface);
@ -163,7 +165,7 @@ static void setup_ipv6(struct net_if *iface, u32_t flags)
return;
}
if (flags & NET_SAMPLE_NEED_ROUTER) {
if (flags & NET_APP_NEED_ROUTER) {
mask |= NET_EVENT_IPV6_ROUTER_ADD;
}
@ -182,7 +184,7 @@ static void setup_ipv6(struct net_if *iface, u32_t flags)
#define setup_ipv6(...)
#endif /* CONFIG_NET_IPV6 */
int net_sample_app_init(const char *app_info, u32_t flags, s32_t timeout)
int net_app_init(const char *app_info, u32_t flags, s32_t timeout)
{
#define LOOP_DEVIDER 10
struct net_if *iface = net_if_get_default();
@ -193,28 +195,11 @@ int net_sample_app_init(const char *app_info, u32_t flags, s32_t timeout)
NET_INFO("%s", app_info);
}
#if defined(CONFIG_NET_L2_BLUETOOTH)
if (bt_enable(NULL)) {
NET_ERR("Bluetooth init failed");
return -EFAULT;
} else {
ipss_init();
ipss_advertise();
}
#endif
#if defined(CONFIG_NET_L2_IEEE802154)
if (ieee802154_sample_setup()) {
NET_ERR("IEEE 802.15.4 setup failed");
return -EFAULT;
}
#endif
if (flags & NET_SAMPLE_NEED_IPV6) {
if (flags & NET_APP_NEED_IPV6) {
count++;
}
if (flags & NET_SAMPLE_NEED_IPV4) {
if (flags & NET_APP_NEED_IPV4) {
count++;
}
@ -252,3 +237,36 @@ int net_sample_app_init(const char *app_info, u32_t flags, s32_t timeout)
return 0;
}
#if defined(CONFIG_NET_APP_AUTO_INIT)
static int init_net_app(struct device *device)
{
u32_t flags = 0;
int ret;
ARG_UNUSED(device);
if (IS_ENABLED(CONFIG_NET_APP_NEED_IPV6)) {
flags |= NET_APP_NEED_IPV6;
}
if (IS_ENABLED(CONFIG_NET_APP_NEED_IPV6_ROUTER)) {
flags |= NET_APP_NEED_ROUTER;
}
if (IS_ENABLED(CONFIG_NET_APP_NEED_IPV4)) {
flags |= NET_APP_NEED_IPV4;
}
/* Initialize the application automatically if needed */
ret = net_app_init("Initializing network", flags,
K_SECONDS(CONFIG_NET_APP_INIT_TIMEOUT));
if (ret < 0) {
NET_ERR("Network initialization failed (%d)", ret);
}
return ret;
}
SYS_INIT(init_net_app, APPLICATION, CONFIG_NET_APP_INIT_PRIO);
#endif /* CONFIG_NET_APP_AUTO_INIT */

1259
subsys/net/lib/app/net_app.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,113 @@
/** @file
* @brief Private net_api API routines
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Print extra info about received TLS data */
#define RX_EXTRA_DEBUG 0
#if defined(MBEDTLS_DEBUG_C)
#include <mbedtls/debug.h>
/* - Debug levels (from ext/lib/crypto/mbedtls/include/mbedtls/debug.h)
* - 0 No debug
* - 1 Error
* - 2 State change
* - 3 Informational
* - 4 Verbose
*/
#if defined(CONFIG_NET_DEBUG_APP_TLS_LEVEL)
#define DEBUG_THRESHOLD CONFIG_NET_DEBUG_APP_TLS_LEVEL
#else
#define DEBUG_THRESHOLD 0
#endif /* CONFIG_NET_DEBUG_APP_TLS_LEVEL */
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
#include <mbedtls/memory_buffer_alloc.h>
#endif
#if defined(MBEDTLS_ERROR_C)
#define _net_app_print_error(fmt, ret) \
do { \
char error[80]; \
\
mbedtls_strerror(ret, error, sizeof(error)); \
\
NET_ERR(fmt " (%s)", -ret, error); \
} while (0)
#else
#define _net_app_print_error(fmt, ret) NET_ERR(fmt, -ret)
#endif
/* Direction of the packet (sending / receiving) */
enum _net_app_dir {
NET_APP_PKT_UNKNOWN = 0,
NET_APP_PKT_TX = 1,
NET_APP_PKT_RX = 2,
};
#define BUF_ALLOC_TIMEOUT 100
#if defined(CONFIG_NET_DEBUG_APP)
void _net_app_print_info(struct net_app_ctx *ctx);
#else
#define _net_app_print_info(...)
#endif /* CONFIG_NET_DEBUG_APP */
#if defined(CONFIG_NET_APP_SERVER) || defined(CONFIG_NET_APP_CLIENT)
char *_net_app_sprint_ipaddr(char *buf, int buflen,
const struct sockaddr *addr);
void _net_app_received(struct net_context *net_ctx,
struct net_pkt *pkt,
int status,
void *user_data);
int _net_app_set_local_addr(struct sockaddr *addr, const char *myaddr,
u16_t port);
int _net_app_set_net_ctx(struct net_app_ctx *ctx,
struct net_context *net_ctx,
struct sockaddr *addr,
socklen_t socklen,
enum net_ip_protocol proto);
int _net_app_config_local_ctx(struct net_app_ctx *ctx,
enum net_sock_type sock_type,
enum net_ip_protocol proto,
struct sockaddr *addr);
struct net_context *_net_app_select_net_ctx(struct net_app_ctx *ctx);
int _net_app_ssl_mux(void *context, unsigned char *buf, size_t size);
int _net_app_tls_sendto(struct net_pkt *pkt,
const struct sockaddr *dst_addr,
socklen_t addrlen,
net_context_send_cb_t cb,
s32_t timeout,
void *token,
void *user_data);
void _net_app_tls_received(struct net_context *context,
struct net_pkt *pkt,
int status,
void *user_data);
int _net_app_ssl_mainloop(struct net_app_ctx *ctx);
#if defined(CONFIG_NET_APP_SERVER)
void _net_app_accept_cb(struct net_context *net_ctx,
struct sockaddr *addr,
socklen_t addrlen,
int status, void *data);
#endif /* CONFIG_NET_APP_SERVER */
#if defined(CONFIG_NET_APP_CLIENT)
#endif /* CONFIG_NET_APP_CLIENT */
#if defined(CONFIG_NET_APP_TLS)
void _net_app_tls_handler_stop(struct net_app_ctx *ctx);
int _net_app_tls_init(struct net_app_ctx *ctx, int client_or_server);
int _net_app_entropy_source(void *data, unsigned char *output, size_t len,
size_t *olen);
int _net_app_ssl_tx(void *context, const unsigned char *buf, size_t size);
#endif /* CONFIG_NET_APP_TLS */
#endif /* CONFIG_NET_APP_SERVER || CONFIG_NET_APP_CLIENT */

363
subsys/net/lib/app/server.c Normal file
View file

@ -0,0 +1,363 @@
/* server.c */
/*
* Copyright (c) 2017 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#if defined(CONFIG_NET_DEBUG_APP)
#define SYS_LOG_DOMAIN "net/app"
#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
#define NET_LOG_ENABLED 1
#endif
#include <zephyr.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <net/net_core.h>
#include <net/net_ip.h>
#include <net/net_if.h>
#include <net/net_app.h>
#include "net_app_private.h"
#if defined(CONFIG_NET_TCP)
static void new_client(struct net_context *net_ctx,
const struct sockaddr *addr)
{
#if defined(CONFIG_NET_DEBUG_APP) && (CONFIG_SYS_LOG_NET_LEVEL > 2)
#if defined(CONFIG_NET_IPV6)
#define PORT_STR sizeof("[]:xxxxx")
char buf[NET_IPV6_ADDR_LEN + PORT_STR];
#elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
#define PORT_STR sizeof(":xxxxx")
char buf[NET_IPV4_ADDR_LEN + PORT_STR];
#endif
NET_INFO("Connection from %s (%p)",
_net_app_sprint_ipaddr(buf, sizeof(buf), addr),
net_ctx);
#endif /* CONFIG_NET_DEBUG_APP */
}
void _net_app_accept_cb(struct net_context *net_ctx,
struct sockaddr *addr,
socklen_t addrlen,
int status, void *data)
{
struct net_app_ctx *ctx = data;
ARG_UNUSED(addr);
ARG_UNUSED(addrlen);
if (status != 0 || ctx->server.net_ctx) {
/* We are already connected and support only one connection at
* a time so this new connection must be closed.
*/
net_context_put(net_ctx);
if (ctx->cb.connect) {
if (!status) {
status = -ECONNREFUSED;
}
ctx->cb.connect(ctx, status, ctx->user_data);
}
if (ctx->server.net_ctx) {
NET_DBG("Already connected via context %p",
ctx->server.net_ctx);
}
return;
}
ctx->server.net_ctx = net_ctx;
new_client(net_ctx, addr);
net_context_recv(net_ctx, ctx->recv_cb, K_NO_WAIT, ctx);
if (ctx->cb.connect) {
ctx->cb.connect(ctx, 0, ctx->user_data);
}
}
#endif /* CONFIG_NET_TCP */
int net_app_listen(struct net_app_ctx *ctx)
{
int ret;
bool dual = false;
if (!ctx) {
return -EINVAL;
}
if (!ctx->is_init) {
return -ENOENT;
}
if (ctx->app_type != NET_APP_SERVER) {
return -EINVAL;
}
#if defined(CONFIG_NET_IPV4)
if (ctx->local.family == AF_UNSPEC) {
ctx->local.family = AF_INET;
dual = true;
_net_app_set_local_addr(&ctx->local, NULL,
net_sin(&ctx->local)->sin_port);
}
ret = _net_app_set_net_ctx(ctx, ctx->ipv4_ctx, &ctx->local,
sizeof(struct sockaddr_in), ctx->proto);
if (ret < 0) {
net_context_put(ctx->ipv4_ctx);
ctx->ipv4_ctx = NULL;
}
#endif
/* We ignore the IPv4 error if IPv6 is enabled */
#if defined(CONFIG_NET_IPV6)
if (ctx->local.family == AF_UNSPEC || dual) {
ctx->local.family = AF_INET6;
_net_app_set_local_addr(&ctx->local, NULL,
net_sin6(&ctx->local)->sin6_port);
}
ret = _net_app_set_net_ctx(ctx, ctx->ipv6_ctx, &ctx->local,
sizeof(struct sockaddr_in6), ctx->proto);
if (ret < 0) {
net_context_put(ctx->ipv6_ctx);
ctx->ipv6_ctx = NULL;
}
#endif
return ret;
}
int net_app_init_server(struct net_app_ctx *ctx,
enum net_sock_type sock_type,
enum net_ip_protocol proto,
struct sockaddr *server_addr,
u16_t port,
void *user_data)
{
int ret;
if (!ctx) {
return -EINVAL;
}
if (ctx->is_init) {
return -EALREADY;
}
memset(&ctx->local, 0, sizeof(ctx->local));
if (server_addr) {
memcpy(&ctx->local, server_addr,
sizeof(ctx->local));
} else {
ctx->local.family = AF_UNSPEC;
if (port == 0) {
return -EINVAL;
}
net_sin(&ctx->local)->sin_port = htons(port);
}
ctx->app_type = NET_APP_SERVER;
ctx->user_data = user_data;
ctx->send_data = net_context_sendto;
ctx->recv_cb = _net_app_received;
ctx->proto = proto;
ctx->sock_type = sock_type;
ret = _net_app_config_local_ctx(ctx, sock_type, proto,
&ctx->local);
if (ret < 0) {
goto fail;
}
ctx->is_init = true;
fail:
return ret;
}
#if defined(CONFIG_NET_APP_TLS)
static inline void new_server(struct net_app_ctx *ctx,
const char *server_banner,
const struct sockaddr *addr)
{
#if defined(CONFIG_NET_DEBUG_APP) && (CONFIG_SYS_LOG_NET_LEVEL > 2)
#if defined(CONFIG_NET_IPV6)
#define PORT_STR sizeof("[]:xxxxx")
char buf[NET_IPV6_ADDR_LEN + PORT_STR];
#elif defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
#define PORT_STR sizeof(":xxxxx")
char buf[NET_IPV4_ADDR_LEN + PORT_STR];
#endif
if (addr) {
NET_INFO("%s %s (%p)", server_banner,
_net_app_sprint_ipaddr(buf, sizeof(buf), addr), ctx);
} else {
NET_INFO("%s (%p)", server_banner, ctx);
}
#endif /* CONFIG_NET_DEBUG_APP */
}
static void tls_server_handler(struct net_app_ctx *ctx,
struct k_sem *startup_sync)
{
int ret;
NET_DBG("Starting TLS server thread for %p", ctx);
ret = _net_app_tls_init(ctx, MBEDTLS_SSL_IS_SERVER);
if (ret < 0) {
NET_DBG("TLS server init failed");
return;
}
k_sem_give(startup_sync);
while (1) {
_net_app_ssl_mainloop(ctx);
mbedtls_ssl_close_notify(&ctx->tls.mbedtls.ssl);
if (ctx->cb.close) {
ctx->cb.close(ctx, -ESHUTDOWN, ctx->user_data);
}
if (ctx->server.net_ctx) {
NET_DBG("Server context %p removed",
ctx->server.net_ctx);
net_context_put(ctx->server.net_ctx);
ctx->server.net_ctx = NULL;
}
}
}
#define TLS_STARTUP_TIMEOUT K_SECONDS(5)
bool net_app_server_tls_enable(struct net_app_ctx *ctx)
{
struct k_sem startup_sync;
NET_ASSERT(ctx);
if (!(ctx->tls.stack && ctx->tls.stack_size > 0)) {
/* No stack or stack size is 0, we cannot enable */
return false;
}
ctx->is_enabled = true;
/* Start the thread that handles TLS traffic. */
if (!ctx->tls.tid) {
k_sem_init(&startup_sync, 0, 1);
ctx->tls.tid = k_thread_create(&ctx->tls.thread,
ctx->tls.stack,
ctx->tls.stack_size,
(k_thread_entry_t)
tls_server_handler,
ctx, &startup_sync, 0,
K_PRIO_COOP(7), 0, 0);
/* Wait until we know that the TLS thread startup was ok */
if (k_sem_take(&startup_sync, TLS_STARTUP_TIMEOUT) < 0) {
NET_ERR("TLS server handler start failed");
_net_app_tls_handler_stop(ctx);
return false;
}
}
return true;
}
bool net_app_server_tls_disable(struct net_app_ctx *ctx)
{
NET_ASSERT(ctx);
ctx->is_enabled = false;
if (!ctx->tls.tid) {
return false;
}
_net_app_tls_handler_stop(ctx);
return true;
}
int net_app_server_tls(struct net_app_ctx *ctx,
u8_t *request_buf,
size_t request_buf_len,
const char *server_banner,
u8_t *personalization_data,
size_t personalization_data_len,
net_app_cert_cb_t cert_cb,
net_app_entropy_src_cb_t entropy_src_cb,
struct k_mem_pool *pool,
u8_t *stack,
size_t stack_size)
{
if (!request_buf || request_buf_len == 0) {
NET_ERR("Request buf must be set");
return -EINVAL;
}
/* mbedtls cannot receive or send larger buffer as what is defined
* in a file pointed by CONFIG_MBEDTLS_CFG_FILE.
*/
if (request_buf_len > MBEDTLS_SSL_MAX_CONTENT_LEN) {
NET_ERR("Request buf too large, max len is %d",
MBEDTLS_SSL_MAX_CONTENT_LEN);
return -EINVAL;
}
if (!cert_cb) {
NET_ERR("Cert callback must be set");
return -EINVAL;
}
if (server_banner) {
new_server(ctx, server_banner, &ctx->local);
}
ctx->tls.request_buf = request_buf;
ctx->tls.request_buf_len = request_buf_len;
ctx->is_tls = true;
ctx->tls.stack = stack;
ctx->tls.stack_size = stack_size;
ctx->tls.mbedtls.cert_cb = cert_cb;
ctx->tls.pool = pool;
if (entropy_src_cb) {
ctx->tls.mbedtls.entropy_src_cb = entropy_src_cb;
} else {
ctx->tls.mbedtls.entropy_src_cb = _net_app_entropy_source;
}
ctx->tls.mbedtls.personalization_data = personalization_data;
ctx->tls.mbedtls.personalization_data_len = personalization_data_len;
ctx->send_data = _net_app_tls_sendto;
ctx->recv_cb = _net_app_tls_received;
/* Then mbedtls specific initialization */
return 0;
}
#endif /* CONFIG_NET_APP_TLS */