diff --git a/boards/arm/frdm_k64f/doc/frdm_k64f.rst b/boards/arm/frdm_k64f/doc/frdm_k64f.rst index b67c5a8c8a0..fc2a98c1678 100644 --- a/boards/arm/frdm_k64f/doc/frdm_k64f.rst +++ b/boards/arm/frdm_k64f/doc/frdm_k64f.rst @@ -76,8 +76,7 @@ The frdm_k64f board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | SPI | on-chip | spi | +-----------+------------+-------------------------------------+ -| ETHERNET | on-chip | ethernet (work in progress, known | -| | | issues exist, see below) | +| ETHERNET | on-chip | ethernet | +-----------+------------+-------------------------------------+ | UART | on-chip | serial port-polling; | | | | serial port-interrupt | @@ -224,13 +223,6 @@ the following message: Hello World! arm -Work in progress and known issues -********************************* - -Ethernet PHY is currently initialized only at the application startup. -For successful initialization, a network cable must be connected between -the board and a host/router. If a cable is not connected when the board -is powered on or reset, the startup will be aborted with an error message. .. _FRDM-K64F Website: http://www.nxp.com/products/software-and-tools/hardware-development-tools/freedom-development-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F diff --git a/drivers/ethernet/Kconfig.mcux b/drivers/ethernet/Kconfig.mcux index 2661f2b91e7..383348e8ab5 100644 --- a/drivers/ethernet/Kconfig.mcux +++ b/drivers/ethernet/Kconfig.mcux @@ -15,6 +15,13 @@ menuconfig ETH_MCUX configuration change. if ETH_MCUX +config ETH_MCUX_PHY_TICK_MS + int "PHY poll period (ms)" + default 1000 + range 100 30000 + help + Set the PHY status polling period. + config ETH_MCUX_RX_BUFFERS int "Number of MCUX RX buffers" depends on ETH_MCUX diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index 2b1111b0898..310f53720e1 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -1,15 +1,12 @@ /* MCUX Ethernet Driver * - * Copyright (c) 2016 ARM Ltd + * Copyright (c) 2016-2017 ARM Ltd * Copyright (c) 2016 Linaro Ltd * * SPDX-License-Identifier: Apache-2.0 */ -/* The driver performs one shot PHY setup. There is no support for - * PHY disconnect, reconnect or configuration change. The PHY setup, - * implemented via MCUX contains polled code that can block the - * initialization thread for a few seconds. +/* Driver Limitations: * * There is no statistics collection for either normal operation or * error behaviour. @@ -30,11 +27,27 @@ #include "fsl_phy.h" #include "fsl_port.h" +enum eth_mcux_phy_state { + eth_mcux_phy_state_initial, + eth_mcux_phy_state_reset, + eth_mcux_phy_state_autoneg, + eth_mcux_phy_state_restart, + eth_mcux_phy_state_read_status, + eth_mcux_phy_state_read_duplex, + eth_mcux_phy_state_wait +}; + struct eth_context { struct net_if *iface; enet_handle_t enet_handle; struct k_sem tx_buf_sem; + enum eth_mcux_phy_state phy_state; + bool link_up; + phy_duplex_t phy_duplex; + phy_speed_t phy_speed; uint8_t mac_addr[6]; + struct k_work phy_work; + struct k_delayed_work delayed_phy_work; /* TODO: FIXME. This Ethernet frame sized buffer is used for * interfacing with MCUX. How it works is that hardware uses * DMA scatter buffers to receive a frame, and then public @@ -70,6 +83,137 @@ rx_buffer[CONFIG_ETH_MCUX_RX_BUFFERS][ETH_MCUX_BUFFER_SIZE]; static uint8_t __aligned(ENET_BUFF_ALIGNMENT) tx_buffer[CONFIG_ETH_MCUX_TX_BUFFERS][ETH_MCUX_BUFFER_SIZE]; +static void eth_mcux_decode_duplex_and_speed(uint32_t status, + phy_duplex_t *p_phy_duplex, + phy_speed_t *p_phy_speed) +{ + switch (status & PHY_CTL1_SPEEDUPLX_MASK) { + case PHY_CTL1_10FULLDUPLEX_MASK: + *p_phy_duplex = kPHY_FullDuplex; + *p_phy_speed = kPHY_Speed10M; + break; + case PHY_CTL1_100FULLDUPLEX_MASK: + *p_phy_duplex = kPHY_FullDuplex; + *p_phy_speed = kPHY_Speed100M; + break; + case PHY_CTL1_100HALFDUPLEX_MASK: + *p_phy_duplex = kPHY_HalfDuplex; + *p_phy_speed = kPHY_Speed100M; + break; + case PHY_CTL1_10HALFDUPLEX_MASK: + *p_phy_duplex = kPHY_HalfDuplex; + *p_phy_speed = kPHY_Speed10M; + break; + } +} + +static void eth_mcux_phy_event(struct eth_context *context) +{ + uint32_t status; + bool link_up; + phy_duplex_t phy_duplex = kPHY_FullDuplex; + phy_speed_t phy_speed = kPHY_Speed100M; + const uint32_t phy_addr = 0; + + SYS_LOG_DBG("phy_state=%d", context->phy_state); + + switch (context->phy_state) { + case eth_mcux_phy_state_initial: + /* Reset the PHY. */ + ENET_StartSMIWrite(ENET, phy_addr, PHY_BASICCONTROL_REG, + kENET_MiiWriteValidFrame, + PHY_BCTL_RESET_MASK); + context->phy_state = eth_mcux_phy_state_reset; + break; + case eth_mcux_phy_state_reset: + /* Setup PHY autonegotiation. */ + ENET_StartSMIWrite(ENET, phy_addr, PHY_AUTONEG_ADVERTISE_REG, + kENET_MiiWriteValidFrame, + (PHY_100BASETX_FULLDUPLEX_MASK | + PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | + PHY_10BASETX_HALFDUPLEX_MASK | 0x1U)); + context->phy_state = eth_mcux_phy_state_autoneg; + break; + case eth_mcux_phy_state_autoneg: + /* Setup PHY autonegotiation. */ + ENET_StartSMIWrite(ENET, phy_addr, PHY_BASICCONTROL_REG, + kENET_MiiWriteValidFrame, + (PHY_BCTL_AUTONEG_MASK | + PHY_BCTL_RESTART_AUTONEG_MASK)); + context->phy_state = eth_mcux_phy_state_restart; + break; + case eth_mcux_phy_state_wait: + case eth_mcux_phy_state_restart: + /* Start reading the PHY basic status. */ + ENET_StartSMIRead(ENET, phy_addr, PHY_BASICSTATUS_REG, + kENET_MiiReadValidFrame); + context->phy_state = eth_mcux_phy_state_read_status; + break; + case eth_mcux_phy_state_read_status: + /* PHY Basic status is available. */ + status = ENET_ReadSMIData(ENET); + link_up = status & PHY_BSTATUS_LINKSTATUS_MASK; + if (link_up && !context->link_up) { + /* Start reading the PHY control register. */ + ENET_StartSMIRead(ENET, phy_addr, PHY_CONTROL1_REG, + kENET_MiiReadValidFrame); + context->link_up = link_up; + context->phy_state = eth_mcux_phy_state_read_duplex; + } else if (!link_up && context->link_up) { + SYS_LOG_INF("Link down"); + context->link_up = link_up; + k_delayed_work_submit(&context->delayed_phy_work, + CONFIG_ETH_MCUX_PHY_TICK_MS); + context->phy_state = eth_mcux_phy_state_wait; + } else { + k_delayed_work_submit(&context->delayed_phy_work, + CONFIG_ETH_MCUX_PHY_TICK_MS); + context->phy_state = eth_mcux_phy_state_wait; + } + + break; + case eth_mcux_phy_state_read_duplex: + /* PHY control register is available. */ + status = ENET_ReadSMIData(ENET); + eth_mcux_decode_duplex_and_speed(status, + &phy_duplex, + &phy_speed); + if (phy_speed != context->phy_speed || + phy_duplex != context->phy_duplex) { + context->phy_speed = phy_speed; + context->phy_duplex = phy_duplex; + ENET_SetMII(ENET, + (enet_mii_speed_t) phy_speed, + (enet_mii_duplex_t) phy_duplex); + } + + SYS_LOG_INF("Enabled %sM %s-duplex mode.", + (phy_speed ? "100" : "10"), + (phy_duplex ? "full" : "half")); + k_delayed_work_submit(&context->delayed_phy_work, + CONFIG_ETH_MCUX_PHY_TICK_MS); + context->phy_state = eth_mcux_phy_state_wait; + break; + } +} + +static void eth_mcux_phy_work(struct k_work *item) +{ + struct eth_context *context = + CONTAINER_OF(item, struct eth_context, phy_work); + + eth_mcux_phy_event(context); +} + +static void eth_mcux_delayed_phy_work(struct k_work *item) +{ + struct eth_context *context = + CONTAINER_OF(item, struct eth_context, delayed_phy_work); + + eth_mcux_phy_event(context); +} + static int eth_tx(struct net_if *iface, struct net_buf *buf) { struct eth_context *context = iface->dev->driver_data; @@ -265,9 +409,6 @@ static int eth_0_init(struct device *dev) struct eth_context *context = dev->driver_data; enet_config_t enet_config; uint32_t sys_clock; - const uint32_t phy_addr = 0x0; - bool link; - status_t status; enet_buffer_config_t buffer_config = { .rxBdNumber = CONFIG_ETH_MCUX_RX_BUFFERS, .txBdNumber = CONFIG_ETH_MCUX_TX_BUFFERS, @@ -281,34 +422,24 @@ static int eth_0_init(struct device *dev) k_sem_init(&context->tx_buf_sem, CONFIG_ETH_MCUX_TX_BUFFERS, CONFIG_ETH_MCUX_TX_BUFFERS); + k_work_init(&context->phy_work, eth_mcux_phy_work); + k_delayed_work_init(&context->delayed_phy_work, + eth_mcux_delayed_phy_work); sys_clock = CLOCK_GetFreq(kCLOCK_CoreSysClk); ENET_GetDefaultConfig(&enet_config); enet_config.interrupt |= kENET_RxFrameInterrupt; enet_config.interrupt |= kENET_TxFrameInterrupt; - - status = PHY_Init(ENET, phy_addr, sys_clock); - if (status) { - SYS_LOG_ERR("PHY_Init() failed: %d", status); - return 1; - } - - PHY_GetLinkStatus(ENET, phy_addr, &link); - if (link) { - phy_speed_t phy_speed; - phy_duplex_t phy_duplex; - - PHY_GetLinkSpeedDuplex(ENET, phy_addr, &phy_speed, &phy_duplex); - enet_config.miiSpeed = (enet_mii_speed_t) phy_speed; - enet_config.miiDuplex = (enet_mii_duplex_t) phy_duplex; - - SYS_LOG_INF("Enabled %dM %s-duplex mode.", - (phy_speed ? 100 : 10), - (phy_duplex ? "full" : "half")); - } else { - SYS_LOG_INF("Link down."); - } + enet_config.interrupt |= kENET_MiiInterrupt; + /* FIXME: Workaround for lack of driver API support for multicast + * management. So, instead we want to receive all multicast + * frames "by default", or otherwise basic IPv6 features, like + * address resolution, don't work. On Kinetis Ethernet controller, + * that translates to enabling promiscuous mode. The real + * fix depends on https://jira.zephyrproject.org/browse/ZEP-1673. + */ + enet_config.macSpecialConfig |= kENET_ControlPromiscuousEnable; #if defined(CONFIG_ETH_MCUX_0_RANDOM_MAC) generate_mac(context->mac_addr); @@ -321,6 +452,8 @@ static int eth_0_init(struct device *dev) context->mac_addr, sys_clock); + ENET_SetSMI(ENET, sys_clock, false); + SYS_LOG_DBG("MAC %02x:%02x:%02x:%02x:%02x:%02x", context->mac_addr[0], context->mac_addr[1], context->mac_addr[2], context->mac_addr[3], @@ -329,6 +462,9 @@ static int eth_0_init(struct device *dev) ENET_SetCallback(&context->enet_handle, eth_callback, dev); eth_0_config_func(); ENET_ActiveRead(ENET); + + k_work_submit(&context->phy_work); + return 0; } @@ -367,11 +503,17 @@ static void eth_mcux_error_isr(void *p) { struct device *dev = p; struct eth_context *context = dev->driver_data; + uint32_t pending = ENET_GetInterruptStatus(ENET); - ENET_ErrorIRQHandler(ENET, &context->enet_handle); + if (pending & ENET_EIR_MII_MASK) { + k_work_submit(&context->phy_work); + ENET_ClearInterruptStatus(ENET, kENET_MiiInterrupt); + } } static struct eth_context eth_0_context = { + .phy_duplex = kPHY_FullDuplex, + .phy_speed = kPHY_Speed100M, .mac_addr = { /* Freescale's OUI */ 0x00, diff --git a/ext/lib/crypto/mbedtls/configs/config-mini-tls1_2.h b/ext/lib/crypto/mbedtls/configs/config-mini-tls1_2.h new file mode 100644 index 00000000000..e39c3cfe0f7 --- /dev/null +++ b/ext/lib/crypto/mbedtls/configs/config-mini-tls1_2.h @@ -0,0 +1,91 @@ +/* + * Minimal configuration for TLS 1.1 (RFC 4346) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Minimal configuration for TLS 1.1 (RFC 4346), implementing only the + * required ciphersuite: MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * + * See README.txt for usage instructions. + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +/* System support */ +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_MEMORY_BUFFER_ALLOC_C +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_PLATFORM_EXIT_ALT +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define MBEDTLS_PLATFORM_PRINTF_ALT + +#if !defined(CONFIG_ARM) +#define MBEDTLS_HAVE_ASM +#endif + +#if defined(CONFIG_MBEDTLS_TEST) +#define MBEDTLS_SELF_TEST +#define MBEDTLS_DEBUG_C +#else +#define MBEDTLS_ENTROPY_C +#endif + +/* mbed TLS feature support */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/* mbed TLS modules */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_DES_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_MD_C +#define MBEDTLS_MD5_C +#define MBEDTLS_OID_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_USE_C + +/* For test certificates */ +#define MBEDTLS_BASE64_C +#define MBEDTLS_CERTS_C +#define MBEDTLS_PEM_PARSE_C + + +#define MBEDTLS_SSL_MAX_CONTENT_LEN 1024 + +#include "mbedtls/check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/include/net/dhcpv4.h b/include/net/dhcpv4.h index 6c0ba84955b..a330debcb93 100644 --- a/include/net/dhcpv4.h +++ b/include/net/dhcpv4.h @@ -28,7 +28,6 @@ enum net_dhcpv4_state { NET_DHCPV4_INIT, NET_DHCPV4_DISCOVER, - NET_DHCPV4_OFFER, NET_DHCPV4_REQUEST, NET_DHCPV4_RENEWAL, NET_DHCPV4_ACK, diff --git a/include/net/mqtt.h b/include/net/mqtt.h index b05d34f37bc..d7d55e63671 100644 --- a/include/net/mqtt.h +++ b/include/net/mqtt.h @@ -17,7 +17,7 @@ */ /** - * @brief mqtt_app MQTT application type + * MQTT application type */ enum mqtt_app { /** Publisher and Subscriber application */ @@ -31,9 +31,9 @@ enum mqtt_app { }; /** - * @brief struct mqtt_ctx MQTT context structure - * @details - * Context structure for the MQTT high-level API with support for QoS. + * MQTT context structure + * + * @details Context structure for the MQTT high-level API with support for QoS. * * This API is designed for asynchronous operation, so callbacks are * executed when some events must be addressed outside the MQTT routines. @@ -74,84 +74,66 @@ struct mqtt_ctx { /** Callback executed when a #MQTT_APP_PUBLISHER application receives * a MQTT PUBxxxx msg. + * If type is MQTT_PUBACK, MQTT_PUBCOMP or MQTT_PUBREC, this callback + * must return 0 if pkt_id matches the packet id of a previously + * received MQTT_PUBxxx message. If this callback returns 0, the caller + * will continue. + * Any other value will stop the QoS handshake and the caller will + * return -EINVAL. The application must discard all the messages + * already processed. * * Note: this callback must be not NULL * - * @param [in] ctx MQTT context - * @param [in] pkt_id Packet Identifier for the input MQTT msg - * @param [in] type Packet type - * @return If this callback returns 0, the caller will - * continue. - * - * @return If type is MQTT_PUBACK, MQTT_PUBCOMP or - * MQTT_PUBREC, this callback must return 0 if - * pkt_id matches the packet id of a previously - * received MQTT_PUBxxx message. - * - * @return Note: the application must discard all the - * messages already processed - * - * @return Any other value will stop the QoS handshake - * and the caller will return -EINVAL + * @param [in] ctx MQTT context + * @param [in] pkt_id Packet Identifier for the input MQTT msg + * @param [in] type Packet type */ int (*publish_tx)(struct mqtt_ctx *ctx, uint16_t pkt_id, enum mqtt_packet type); /** Callback executed when a MQTT_APP_SUBSCRIBER, - * MQTT_APP_PUBLISHER_SUBSCRIBER or MQTT_APP_SERVER application receive - * a MQTT PUBxxxx msg. + * MQTT_APP_PUBLISHER_SUBSCRIBER or MQTT_APP_SERVER applications receive + * a MQTT PUBxxxx msg. If this callback returns 0, the caller will + * continue. If type is MQTT_PUBREL this callback must return 0 if + * pkt_id matches the packet id of a previously received MQTT_PUBxxx + * message. Any other value will stop the QoS handshake and the caller + * will return -EINVAL * * Note: this callback must be not NULL * - * @param [in] ctx MQTT context - * @param [in] msg Publish message, this parameter is only used - * when the type is MQTT_PUBLISH - * @param [in] pkt_id Packet Identifier for the input msg - * @param [in] type Packet type - * @return If this callback returns 0, the caller will - * continue. - * - * @return If type is MQTT_PUBREL this callback must return - * 0 if pkt_id matches the packet id of a - * previously received MQTT_PUBxxx message. - * - * @return Note: the application must discard all the - * messages already processed - * - * @return Any other value will stop the QoS handshake - * and the caller will return -EINVAL + * @param [in] ctx MQTT context + * @param [in] msg Publish message, this parameter is only used + * when the type is MQTT_PUBLISH + * @param [in] pkt_id Packet Identifier for the input msg + * @param [in] type Packet type */ int (*publish_rx)(struct mqtt_ctx *ctx, struct mqtt_publish_msg *msg, uint16_t pkt_id, enum mqtt_packet type); /** Callback executed when a MQTT_APP_SUBSCRIBER or * MQTT_APP_PUBLISHER_SUBSCRIBER receives the MQTT SUBACK message + * If this callback returns 0, the caller will continue. Any other + * value will make the caller return -EINVAL. * * Note: this callback must be not NULL * - * @param [in] ctx MQTT context - * @param [in] pkt_id Packet Identifier for the MQTT SUBACK msg - * @param [in] items Number of elements in the qos array - * @param [in] qos Array of QoS values - * @return If this callback returns 0, the caller will - * continue - * @return Any other value will make the caller return - * -EINVAL + * @param [in] ctx MQTT context + * @param [in] pkt_id Packet Identifier for the MQTT SUBACK msg + * @param [in] items Number of elements in the qos array + * @param [in] qos Array of QoS values */ int (*subscribe)(struct mqtt_ctx *ctx, uint16_t pkt_id, uint8_t items, enum mqtt_qos qos[]); /** Callback executed when a MQTT_APP_SUBSCRIBER or * MQTT_APP_PUBLISHER_SUBSCRIBER receives the MQTT UNSUBACK message + * If this callback returns 0, the caller will continue. Any other value + * will make the caller return -EINVAL * * Note: this callback must be not NULL * * @param [in] ctx MQTT context * @param [in] pkt_id Packet Identifier for the MQTT SUBACK msg - * @return If this callback returns 0, the caller will - * continue - * @return Any other value will make the caller return - * -EINVAL */ int (*unsubscribe)(struct mqtt_ctx *ctx, uint16_t pkt_id); @@ -182,219 +164,253 @@ struct mqtt_ctx { }; /** - * @brief mqtt_init Initializes the MQTT context structure - * @param ctx MQTT context structure - * @param app_type See enum mqtt_app - * @return 0, always. + * Initializes the MQTT context structure + * + * @param ctx MQTT context structure + * @param app_type See enum mqtt_app + * @retval 0, always. */ int mqtt_init(struct mqtt_ctx *ctx, enum mqtt_app app_type); /** - * @brief mqtt_tx_connect Sends the MQTT CONNECT message - * @param [in] ctx MQTT context structure - * @param [in] msg MQTT CONNECT msg - * @return 0 on success - * @return -EIO on network error - * @return -ENOMEM if no data/tx buffer is available - * @return -EINVAL if invalid data was passed to this - * routine + * Sends the MQTT CONNECT message + * + * @param [in] ctx MQTT context structure + * @param [in] msg MQTT CONNECT msg + * + * @retval 0 on success + * @retval -EIO + * @retval -ENOMEM + * @retval -EINVAL */ int mqtt_tx_connect(struct mqtt_ctx *ctx, struct mqtt_connect_msg *msg); /** - * @brief mqtt_tx_disconnect Send the MQTT DISCONNECT message - * @param [in] ctx MQTT context structure - * @return 0 on success - * @return -EIO on network error - * @return -ENOMEM if no data/tx buffer is available - * @return -EINVAL if invalid data was passed to this - * routine + * Send the MQTT DISCONNECT message + * + * @param [in] ctx MQTT context structure + * + * @retval 0 on success + * @retval -EIO + * @retval -ENOMEM + * @retval -EINVAL */ int mqtt_tx_disconnect(struct mqtt_ctx *ctx); /** - * @brief mqtt_tx_puback Sends the MQTT PUBACK message with the given - * packet id - * @param [in] ctx MQTT context structure - * @param [in] id MQTT Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Sends the MQTT PUBACK message with the given packet id + * + * @param [in] ctx MQTT context structure + * @param [in] id MQTT Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_puback(struct mqtt_ctx *ctx, uint16_t id); /** - * @brief mqtt_tx_pubcomp Sends the MQTT PUBCOMP message with the given - * packet id - * @param [in] ctx MQTT context structure - * @param [in] id MQTT Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Sends the MQTT PUBCOMP message with the given packet id + * + * @param [in] ctx MQTT context structure + * @param [in] id MQTT Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_pubcomp(struct mqtt_ctx *ctx, uint16_t id); /** - * @brief mqtt_tx_pubrec Sends the MQTT PUBREC message with the given - * packet id - * @param [in] ctx MQTT context structure - * @param [in] id MQTT Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Sends the MQTT PUBREC message with the given packet id + * + * @param [in] ctx MQTT context structure + * @param [in] id MQTT Packet Identifier + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_pubrec(struct mqtt_ctx *ctx, uint16_t id); /** - * @brief mqtt_tx_pubrel Sends the MQTT PUBREL message with the given - * packet id - * @param [in] ctx MQTT context structure - * @param [in] id MQTT Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Sends the MQTT PUBREL message with the given packet id + * + * @param [in] ctx MQTT context structure + * @param [in] id MQTT Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_pubrel(struct mqtt_ctx *ctx, uint16_t id); /** - * @brief mqtt_tx_publish Sends the MQTT PUBLISH message - * @param [in] ctx MQTT context structure - * @param [in] msg MQTT PUBLISH msg - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Sends the MQTT PUBLISH message + * + * @param [in] ctx MQTT context structure + * @param [in] msg MQTT PUBLISH msg + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_publish(struct mqtt_ctx *ctx, struct mqtt_publish_msg *msg); /** - * @brief mqtt_tx_pingreq Sends the MQTT PINGREQ message - * @param [in] ctx MQTT context structure - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Sends the MQTT PINGREQ message + * + * @param [in] ctx MQTT context structure + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_pingreq(struct mqtt_ctx *ctx); /** - * @brief mqtt_tx_subscribe Sends the MQTT SUBSCRIBE message - * @param [in] ctx MQTT context structure - * @param [in] pkt_id Packet identifier for the MQTT SUBSCRIBE msg - * @param [in] items Number of elements in 'topics' and 'qos' arrays - * @param [in] topics Array of 'items' elements containing C strings. - * For example: {"sensors", "lights", "doors"} - * @param [in] qos Array of 'items' elements containing MQTT QoS - * values: MQTT_QoS0, MQTT_QoS1, MQTT_QoS2. For - * example for the 'topics' array above the - * following QoS may be used: - * {MQTT_QoS0, MQTT_QoS2, MQTT_QoS1}, indicating - * that the subscription to 'lights' must be done - * with MQTT_QoS2 - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Sends the MQTT SUBSCRIBE message + * + * @param [in] ctx MQTT context structure + * @param [in] pkt_id Packet identifier for the MQTT SUBSCRIBE msg + * @param [in] items Number of elements in 'topics' and 'qos' arrays + * @param [in] topics Array of 'items' elements containing C strings. + * For example: {"sensors", "lights", "doors"} + * @param [in] qos Array of 'items' elements containing MQTT QoS values: + * MQTT_QoS0, MQTT_QoS1, MQTT_QoS2. For example for the 'topics' + * array above the following QoS may be used: {MQTT_QoS0, + * MQTT_QoS2, MQTT_QoS1}, indicating that the subscription to + * 'lights' must be done with MQTT_QoS2 + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_subscribe(struct mqtt_ctx *ctx, uint16_t pkt_id, uint8_t items, const char *topics[], const enum mqtt_qos qos[]); /** - * @brief mqtt_tx_unsubscribe Sends the MQTT UNSUBSCRIBE message - * @param [in] ctx MQTT context structure - * @param [in] pkt_id Packet identifier for the MQTT UNSUBSCRIBE msg - * @param [in] items Number of elements in the 'topics' array - * @param [in] topics Array of 'items' elements containing C strings - * @return + * Sends the MQTT UNSUBSCRIBE message + * + * @param [in] ctx MQTT context structure + * @param [in] pkt_id Packet identifier for the MQTT UNSUBSCRIBE msg + * @param [in] items Number of elements in the 'topics' array + * @param [in] topics Array of 'items' elements containing C strings + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM + * @retval -EIO */ int mqtt_tx_unsubscribe(struct mqtt_ctx *ctx, uint16_t pkt_id, uint8_t items, const char *topics[]); + +/** + * Parses and validates the MQTT CONNACK msg + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * @param [in] clean_session MQTT clean session parameter + * + * @retval 0 on success + * @retval -EINVAL + */ int mqtt_rx_connack(struct mqtt_ctx *ctx, struct net_buf *rx, int clean_session); /** - * @brief mqtt_rx_puback Parses and validates the MQTT PUBACK message - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error + * Parses and validates the MQTT PUBACK message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_rx_puback(struct mqtt_ctx *ctx, struct net_buf *rx); /** - * @brief mqtt_rx_pubcomp Parses and validates the MQTT PUBCOMP message - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error + * Parses and validates the MQTT PUBCOMP message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_rx_pubcomp(struct mqtt_ctx *ctx, struct net_buf *rx); /** - * @brief mqtt_rx_pubrec Parses and validates the MQTT PUBREC message - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error + * Parses and validates the MQTT PUBREC message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_rx_pubrec(struct mqtt_ctx *ctx, struct net_buf *rx); /** - * @brief mqtt_rx_pubrel Parses and validates the MQTT PUBREL message - * @details rx is an RX buffer from the IP stack - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error + * Parses and validates the MQTT PUBREL message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_rx_pubrel(struct mqtt_ctx *ctx, struct net_buf *rx); /** - * @brief mqtt_rx_pingresp Parses the MQTT PINGRESP message - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error + * Parses the MQTT PINGRESP message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_rx_pingresp(struct mqtt_ctx *ctx, struct net_buf *rx); /** - * @brief mqtt_rx_suback Parses the MQTT SUBACK message - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error + * Parses the MQTT SUBACK message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_rx_suback(struct mqtt_ctx *ctx, struct net_buf *rx); /** - * @brief mqtt_rx_unsuback Parses the MQTT UNSUBACK message - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error + * Parses the MQTT UNSUBACK message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_rx_unsuback(struct mqtt_ctx *ctx, struct net_buf *rx); /** - * @brief mqtt_rx_publish Parses the MQTT PUBLISH message - * @param [in] ctx MQTT context structure - * @param [in] rx Data buffer - * @return 0 on success - * @return -EINVAL on error - * @return -ENOMEM if no data buffer is available + * Parses the MQTT PUBLISH message + * + * @param [in] ctx MQTT context structure + * @param [in] rx Data buffer + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM */ int mqtt_rx_publish(struct mqtt_ctx *ctx, struct net_buf *rx); diff --git a/include/net/zoap.h b/include/net/zoap.h index b035d4c8392..e255efd8564 100644 --- a/include/net/zoap.h +++ b/include/net/zoap.h @@ -147,16 +147,18 @@ struct zoap_reply; struct zoap_resource; /** - * Type of the callback being called when a resource's method is invoked by - * remote entity. + * @typedef zoap_method_t + * @brief Type of the callback being called when a resource's method is + * invoked by the remote entity. */ typedef int (*zoap_method_t)(struct zoap_resource *resource, struct zoap_packet *request, const struct sockaddr *from); /** - * Type of the callback being called when a resource's has observers to be - * informed when an update happens. + * @typedef zoap_notify_t + * @brief Type of the callback being called when a resource's has observers + * to be informed when an update happens. */ typedef void (*zoap_notify_t)(struct zoap_resource *resource, struct zoap_observer *observer); @@ -168,6 +170,7 @@ typedef void (*zoap_notify_t)(struct zoap_resource *resource, * them, by fetching their state or requesting updates to them. */ struct zoap_resource { + /** Which function to be called for each CoAP method */ zoap_method_t get, post, put, del; zoap_notify_t notify; const char * const *path; @@ -177,7 +180,7 @@ struct zoap_resource { }; /** - * Represents a remote device that is observing a local resource. + * @brief Represents a remote device that is observing a local resource. */ struct zoap_observer { sys_snode_t list; @@ -187,7 +190,7 @@ struct zoap_observer { }; /** - * Representation of a CoAP packet. + * @brief Representation of a CoAP packet. */ struct zoap_packet { struct net_buf *buf; @@ -196,7 +199,8 @@ struct zoap_packet { }; /** - * Helper function to be called when a response matches the + * @typedef zoap_reply_t + * @brief Helper function to be called when a response matches the * a pending request. */ typedef int (*zoap_reply_t)(const struct zoap_packet *response, @@ -204,7 +208,7 @@ typedef int (*zoap_reply_t)(const struct zoap_packet *response, const struct sockaddr *from); /** - * Represents a request awaiting for an acknowledgment (ACK). + * @brief Represents a request awaiting for an acknowledgment (ACK). */ struct zoap_pending { struct zoap_packet request; @@ -212,8 +216,8 @@ struct zoap_pending { }; /** - * Represents the handler for the reply of a request, it is also used when - * observing resources. + * @brief Represents the handler for the reply of a request, it is + * also used when observing resources. */ struct zoap_reply { zoap_reply_t reply; @@ -224,48 +228,76 @@ struct zoap_reply { }; /** - * Indicates that the remote device referenced by @a addr, with @a request, - * wants to observe a resource. + * @brief Indicates that the remote device referenced by @a addr, with + * @a request, wants to observe a resource. + * + * @param observer Observer to be initialized + * @param request Request on which the observer will be based + * @param addr Address of the remote device */ void zoap_observer_init(struct zoap_observer *observer, const struct zoap_packet *request, const struct sockaddr *addr); /** - * After the observer is initialized, associate the observer with an resource. - * Returns whether this is the first observer added to this resource. + * @brief After the observer is initialized, associate the observer + * with an resource. + * + * @param resource Resource to add an observer + * @param observer Observer to be added + * + * @return true if this is the first observer added to this resource. */ bool zoap_register_observer(struct zoap_resource *resource, struct zoap_observer *observer); /** - * Remove this observer from the list of registered observers of - * that resource. + * @brief Remove this observer from the list of registered observers + * of that resource. + * + * @param resource Resource in which to remove the observer + * @param observer Observer to be removed */ void zoap_remove_observer(struct zoap_resource *resource, struct zoap_observer *observer); /** - * Returns the observer that matches address @a addr. + * @brief Returns the observer that matches address @a addr. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * @param addr Address of the endpoint observing a resource + * + * @return A pointer to a observer if a match is found, NULL + * otherwise. */ struct zoap_observer *zoap_find_observer_by_addr( struct zoap_observer *observers, size_t len, const struct sockaddr *addr); /** - * Returns the next available observer representation. + * @brief Returns the next available observer representation. + * + * @param observers Pointer to the array of observers + * @param len Size of the array of observers + * + * @return A pointer to a observer if there's an available observer, + * NULL otherwise. */ struct zoap_observer *zoap_observer_next_unused( struct zoap_observer *observers, size_t len); /** - * Indicates that a reply is expected for @a request. + * @brief Indicates that a reply is expected for @a request. + * + * @param reply Reply structure to be initialized + * @param request Request from which @a reply will be based */ void zoap_reply_init(struct zoap_reply *reply, const struct zoap_packet *request); /** - * Represents the value of a CoAP option. + * @brief Represents the value of a CoAP option. * * To be used with zoap_find_options(). */ @@ -275,51 +307,97 @@ struct zoap_option { }; /** - * Parses the CoAP packet in @a buf, validating it and initializing @a pkt. - * @a buf must remain valid while @a pkt is used. Used when receiving packets. + * @brief Parses the CoAP packet in @a buf, validating it and + * initializing @a pkt. @a buf must remain valid while @a pkt is used. + * + * @param pkt Packet to be initialized from received @a buf. + * @param buf Buffer containing a CoAP packet, its @a data pointer is + * positioned on the start of the CoAP packet. + * + * @return 0 in case of success or negative in case of error. */ int zoap_packet_parse(struct zoap_packet *pkt, struct net_buf *buf); /** - * Creates a new CoAP packet from a net_buf. @a buf must remain valid while - * @a pkt is used. Used when creating packets to be sent. + * @brief Creates a new CoAP packet from a net_buf. @a buf must remain + * valid while @a pkt is used. + * + * @param pkt New packet to be initialized using the storage from @a + * buf. + * @param buf Buffer that will contain a CoAP packet + * + * @return 0 in case of success or negative in case of error. */ int zoap_packet_init(struct zoap_packet *pkt, struct net_buf *buf); /** - * Initialize a pending request with a request. The request's fields are - * copied into the pending struct, so @a request doesn't have to live for as - * long as the pending struct lives, but net_buf needs to live for at least - * that long. + * @brief Initialize a pending request with a request. + * + * The request's fields are copied into the pending struct, so @a + * request doesn't have to live for as long as the pending struct + * lives, but net_buf needs to live for at least that long. + * + * @param pending Structure representing the waiting for a + * confirmation message, initialized with data from @a request + * @param request Message waiting for confirmation + * + * @return 0 in case of success or negative in case of error. */ int zoap_pending_init(struct zoap_pending *pending, const struct zoap_packet *request); /** - * Returns the next available pending struct, that can be used to track - * the retransmission status of a request. + * @brief Returns the next available pending struct, that can be used + * to track the retransmission status of a request. + * + * @param pendings Pointer to the array of #zoap_pending structures + * @param len Size of the array of #zoap_pending structures + * + * @return pointer to a free #zoap_pending structure, NULL in case + * none could be found. */ struct zoap_pending *zoap_pending_next_unused( struct zoap_pending *pendings, size_t len); /** - * Returns the next available reply struct, so it can be used to track replies - * and notifications received. + * @brief Returns the next available reply struct, so it can be used + * to track replies and notifications received. + * + * @param replies Pointer to the array of #zoap_reply structures + * @param len Size of the array of #zoap_reply structures + * + * @return pointer to a free #zoap_reply structure, NULL in case + * none could be found. */ struct zoap_reply *zoap_reply_next_unused( struct zoap_reply *replies, size_t len); /** - * After a response is received, clear all pending retransmissions related to - * that response. + * @brief After a response is received, clear all pending + * retransmissions related to that response. + * + * @param response The received response + * @param pendings Pointer to the array of #zoap_reply structures + * @param len Size of the array of #zoap_reply structures + * + * @return pointer to the associated #zoap_pending structure, NULL in + * case none could be found. */ struct zoap_pending *zoap_pending_received( const struct zoap_packet *response, struct zoap_pending *pendings, size_t len); /** - * After a response is received, clear all pending retransmissions related to - * that response. + * @brief After a response is received, clear all pending + * retransmissions related to that response. + * + * @param response A response received + * @param from Address from which the response was received + * @param replies Pointer to the array of #zoap_reply structures + * @param len Size of the array of #zoap_reply structures + * + * @return Pointer to the reply matching the packet received, NULL if + * none could be found. */ struct zoap_reply *zoap_response_received( const struct zoap_packet *response, @@ -327,91 +405,170 @@ struct zoap_reply *zoap_response_received( struct zoap_reply *replies, size_t len); /** - * Returns the next pending about to expire, pending->timeout informs how many - * ms to next expiration. + * @brief Returns the next pending about to expire, pending->timeout + * informs how many ms to next expiration. + * + * @param pendings Pointer to the array of #zoap_pending structures + * @param len Size of the array of #zoap_pending structures + * + * @return The next #zoap_pending to expire, NULL if none is about to + * expire. */ struct zoap_pending *zoap_pending_next_to_expire( struct zoap_pending *pendings, size_t len); /** - * After a request is sent, user may want to cycle the pending retransmission - * so the timeout is updated. Returns false if this is the last - * retransmission. + * @brief After a request is sent, user may want to cycle the pending + * retransmission so the timeout is updated. + * + * @param pending Pending representation to have its timeout updated + * + * @return false if this is the last retransmission. */ bool zoap_pending_cycle(struct zoap_pending *pending); /** - * Cancels the pending retransmission, so it again becomes available. + * @brief Cancels the pending retransmission, so it again becomes + * available. + * + * @param pending Pending representation to be canceled */ void zoap_pending_clear(struct zoap_pending *pending); /** - * Cancels awaiting for this reply, so it becomes available again. + * @brief Cancels awaiting for this reply, so it becomes available + * again. + * + * @param reply The reply to be cancelled */ void zoap_reply_clear(struct zoap_reply *reply); /** - * When a request is received, call the appropriate methods of the - * matching resources. + * @brief When a request is received, call the appropriate methods of + * the matching resources. + * + * @param pkt Packet received + * @param resources Array of known resources + * @param from Address from which the packet was received + * + * @return 0 in case of success or negative in case of error. */ int zoap_handle_request(struct zoap_packet *pkt, struct zoap_resource *resources, const struct sockaddr *from); /** - * Indicates that this resource was updated and that the @a notify callback - * should be called for every registered observer. + * @brief Indicates that this resource was updated and that the @a + * notify callback should be called for every registered observer. + * + * @param resource Resource that was updated + * + * @return 0 in case of success or negative in case of error. */ int zoap_resource_notify(struct zoap_resource *resource); /** - * Returns if this request is enabling observing a resource. + * @brief Returns if this request is enabling observing a resource. + * + * @param request Request to be checked + * + * @return True if the request is enabling observing a resource, False + * otherwise */ bool zoap_request_is_observe(const struct zoap_packet *request); /** - * Returns a pointer to the start of the payload, and how much memory - * is available (to the payload), it will also insert the - * COAP_MARKER (0xFF). When the payload is already set, for example, - * for incoming packets, it will return how many bytes the payload - * occupies. + * @brief Returns a pointer to the start of the payload and its size + * + * It will insert the COAP_MARKER (0xFF), if its not set, and return the + * available size for the payload. + * + * @param pkt Packet to get (or insert) the payload + * @param len Amount of space for the payload + * + * @return pointer to the start of the payload, NULL in case of error. */ uint8_t *zoap_packet_get_payload(struct zoap_packet *pkt, uint16_t *len); /** - * Returns the internal buffer of the CoAP packet, appending the - * COAP_MARKER to the buffer if necessary. + * @brief Returns the internal buffer of the CoAP packet, appending + * the COAP_MARKER to the buffer if necessary. + * + * @param pkt Packet to get (or insert) the payload + * + * @return pointer to the net_buf storing the payload. */ struct net_buf *zoap_packet_get_buf(struct zoap_packet *pkt); /** - * Sets how much space was used by the payload. + * @brief Sets how much space was used by the payload. + * + * Used for outgoing packets, after zoap_packet_get_payload(), to + * update the internal representation with the amount of data that was + * added to the packet. + * + * @param pkt Packet to be updated + * @param len Amount of data that was added to the payload + * + * @return 0 in case of success or negative in case of error. */ int zoap_packet_set_used(struct zoap_packet *pkt, uint16_t len); /** - * Adds an option to the packet. Note that options must be added - * in numeric order of their codes. + * @brief Adds an option to the packet. + * + * Note: ptions must be added in numeric order of their codes. + * + * @param pkt Packet to be updated + * @param code Option code to add to the packet, see #zoap_option_num + * @param value Pointer to the value of the option, will be copied to the packet + * @param len Size of the data to be added + * + * @return 0 in case of success or negative in case of error. */ int zoap_add_option(struct zoap_packet *pkt, uint16_t code, const void *value, uint16_t len); /** - * Converts an option to its integer representation. It assumes that - * the number is encoded in the network byte order in the option. + * @brief Converts an option to its integer representation. + * + * Assumes that the number is encoded in the network byte order in the + * option. + * + * @param option Pointer to the option value, retrieved by + * zoap_find_options() + * + * @return The integer representation of the option */ unsigned int zoap_option_value_to_int(const struct zoap_option *option); /** - * Adds an integer value option to the packet. The option must be - * added in numeric order of their codes, and the least amount of - * bytes will be used to encode the value. + * @brief Adds an integer value option to the packet. + * + * The option must be added in numeric order of their codes, and the + * least amount of bytes will be used to encode the value. + * + * @param pkt Packet to be updated + * @param code Option code to add to the packet, see #zoap_option_num + * @param val Integer value to be added + * + * @return 0 in case of success or negative in case of error. */ int zoap_add_option_int(struct zoap_packet *pkt, uint16_t code, unsigned int val); /** - * Return the values associated with the option of value @a code. + * @brief Return the values associated with the option of value @a + * code. + * + * @param pkt CoAP packet representation + * @param code Option number to look for + * @param options Array of #zoap_option where to store the value + * of the options found + * @param veclen Number of elements in the options array + * + * @return The number of options found in packet matching code, + * negative on error. */ int zoap_find_options(const struct zoap_packet *pkt, uint16_t code, struct zoap_option *options, uint16_t veclen); @@ -435,7 +592,12 @@ enum zoap_block_size { }; /** - * Helper for converting the enumeration to the size expressed in bytes. + * @brief Helper for converting the enumeration to the size expressed + * in bytes. + * + * @param block_size The block size to be converted + * + * @return The size in bytes that the block_size represents */ static inline uint16_t zoap_block_size_to_bytes( enum zoap_block_size block_size) @@ -444,7 +606,7 @@ static inline uint16_t zoap_block_size_to_bytes( } /** - * Represents the current state of a block-wise transaction. + * @brief Represents the current state of a block-wise transaction. */ struct zoap_block_context { size_t total_size; @@ -453,103 +615,186 @@ struct zoap_block_context { }; /** - * Initializes the context of a block-wise transfer. + * @brief Initializes the context of a block-wise transfer. + * + * @param ctx The context to be initialized + * @param block_size The size of the block + * @param total_size The total size of the transfer, if known + * + * @return 0 in case of success or negative in case of error. */ int zoap_block_transfer_init(struct zoap_block_context *ctx, - enum zoap_block_size block_size, - size_t total_size); + enum zoap_block_size block_size, + size_t total_size); /** - * Add BLOCK1 option to the packet. + * @brief Add BLOCK1 option to the packet. + * + * @param pkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Block1 option + * + * @return 0 in case of success or negative in case of error. */ int zoap_add_block1_option(struct zoap_packet *pkt, struct zoap_block_context *ctx); /** - * Add BLOCK2 option to the packet. + * @brief Add BLOCK2 option to the packet. + * + * @param pkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Block2 option + * + * @return 0 in case of success or negative in case of error. */ int zoap_add_block2_option(struct zoap_packet *pkt, struct zoap_block_context *ctx); /** - * Add SIZE1 option to the packet. + * @brief Add SIZE1 option to the packet. + * + * @param pkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Size1 option + * + * @return 0 in case of success or negative in case of error. */ int zoap_add_size1_option(struct zoap_packet *pkt, struct zoap_block_context *ctx); /** - * Add SIZE2 option to the packet. + * @brief Add SIZE2 option to the packet. + * + * @param pkt Packet to be updated + * @param ctx Block context from which to retrieve the + * information for the Size2 option + * + * @return 0 in case of success or negative in case of error. */ int zoap_add_size2_option(struct zoap_packet *pkt, struct zoap_block_context *ctx); /** - * Retrieves BLOCK{1,2} and SIZE{1,2} from @a pkt and updates + * @brief Retrieves BLOCK{1,2} and SIZE{1,2} from @a pkt and updates * @a ctx accordingly. * - * Returns an error if the packet contains invalid options. + * @param pkt Packet in which to look for block-wise transfers options + * @param ctx Block context to be updated + * + * @return 0 in case of success or negative in case of error. */ -int zoap_update_from_block(struct zoap_packet *pkt, +int zoap_update_from_block(const struct zoap_packet *pkt, struct zoap_block_context *ctx); + /** - * Updates @a ctx so after this is called the current entry + * @brief Updates @a ctx so after this is called the current entry * indicates the correct offset in the body of data being * transferred. + * + * @param ctx Block context to be updated + * + * @return The offset in the block-wise transfer, 0 if the transfer + * has finished. */ size_t zoap_next_block(struct zoap_block_context *ctx); /** - * Returns the version present in a CoAP packet. + * @brief Returns the version present in a CoAP packet. + * + * @param pkt CoAP packet representation + * + * @return the CoAP version in packet */ uint8_t zoap_header_get_version(const struct zoap_packet *pkt); /** - * Returns the type of the packet present in the CoAP packet. + * @brief Returns the type of the CoAP packet. + * + * @param pkt CoAP packet representation + * + * @return the type of the packet */ uint8_t zoap_header_get_type(const struct zoap_packet *pkt); /** - * Returns the token associated with a CoAP packet. + * @brief Returns the token (if any) in the CoAP packet. + * + * @param pkt CoAP packet representation + * @param len Where to store the length of the token + * + * @return pointer to the start of the token in the CoAP packet. */ const uint8_t *zoap_header_get_token(const struct zoap_packet *pkt, uint8_t *len); /** - * Returns the code present in the header of a CoAP packet. + * @brief Returns the code of the CoAP packet. + * + * @param pkt CoAP packet representation + * + * @return the code present in the packet */ uint8_t zoap_header_get_code(const struct zoap_packet *pkt); /** - * Returns the message id associated with a CoAP packet. + * @brief Returns the message id associated with the CoAP packet. + * + * @param pkt CoAP packet representation + * + * @return the message id present in the packet */ uint16_t zoap_header_get_id(const struct zoap_packet *pkt); /** - * Sets the CoAP version present in the CoAP header of a packet. + * @brief Sets the version of the CoAP packet. + * + * @param pkt CoAP packet representation + * @param ver The CoAP version to set in the packet */ void zoap_header_set_version(struct zoap_packet *pkt, uint8_t ver); /** - * Sets the type of a CoAP message. + * @brief Sets the type of the CoAP packet. + * + * @param pkt CoAP packet representation + * @param type The packet type to set */ void zoap_header_set_type(struct zoap_packet *pkt, uint8_t type); /** - * Sets the token present in the CoAP header of a packet. + * @brief Sets the token in the CoAP packet. + * + * @param pkt CoAP packet representation + * @param token Token to set in the packet, will be copied + * @param tokenlen Size of the token to be set, 8 bytes maximum + * + * @return 0 in case of success or negative in case of error. */ int zoap_header_set_token(struct zoap_packet *pkt, const uint8_t *token, uint8_t tokenlen); /** - * Sets the code present in the header of a CoAP packet. + * @brief Sets the code present in the CoAP packet. + * + * @param pkt CoAP packet representation + * @param code The code set in the packet */ void zoap_header_set_code(struct zoap_packet *pkt, uint8_t code); /** - * Sets the message id associated with a CoAP packet. + * @brief Sets the message id present in the CoAP packet. + * + * @param pkt CoAP packet representation + * @param id The message id to set in the packet */ void zoap_header_set_id(struct zoap_packet *pkt, uint16_t id); +/** + * @brief Helper to generate message ids + * + * @return a new message id + */ static inline uint16_t zoap_next_id(void) { static uint16_t message_id; @@ -558,8 +803,10 @@ static inline uint16_t zoap_next_id(void) } /** - * Returns a randomly generated array of 8 bytes, that can be used as a - * message's token. + * @brief Returns a randomly generated array of 8 bytes, that can be + * used as a message's token. + * + * @return a 8-byte pseudo-random token. */ uint8_t *zoap_next_token(void); diff --git a/lib/libc/minimal/include/time.h b/lib/libc/minimal/include/time.h new file mode 100644 index 00000000000..ecb198e1ac8 --- /dev/null +++ b/lib/libc/minimal/include/time.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/* Dummy time.h to fulfill the requirements of certain libraries + * i.e. mbedTLS + */ diff --git a/samples/net/dns_client/prj_qemu_x86.conf b/samples/net/dns_client/prj_qemu_x86.conf index 39410474949..9f09444f12a 100644 --- a/samples/net/dns_client/prj_qemu_x86.conf +++ b/samples/net/dns_client/prj_qemu_x86.conf @@ -29,5 +29,5 @@ CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=1 CONFIG_NET_SAMPLES_IP_ADDRESSES=y CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1" CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2" -CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.168.1.101" -CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.168.1.10" +CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.2" diff --git a/samples/net/echo_client/prj_qemu_cortex_m3.conf b/samples/net/echo_client/prj_qemu_cortex_m3.conf new file mode 100644 index 00000000000..b26453750e4 --- /dev/null +++ b/samples/net/echo_client/prj_qemu_cortex_m3.conf @@ -0,0 +1,26 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_LOG=y +CONFIG_NET_SLIP_TAP=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_INIT_STACKS=y +CONFIG_PRINTK=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_NBUF_RX_COUNT=14 +CONFIG_NET_NBUF_TX_COUNT=14 +CONFIG_NET_NBUF_DATA_COUNT=30 +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 +CONFIG_NET_MAX_CONTEXTS=10 + +CONFIG_NET_SHELL=y + +CONFIG_NET_SAMPLES_IP_ADDRESSES=y +CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::2" +CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::1" +CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.2" +CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.1" diff --git a/samples/net/echo_server/prj_qemu_cortex_m3.conf b/samples/net/echo_server/prj_qemu_cortex_m3.conf new file mode 100644 index 00000000000..663d5d73d50 --- /dev/null +++ b/samples/net/echo_server/prj_qemu_cortex_m3.conf @@ -0,0 +1,27 @@ + +CONFIG_NETWORKING=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=y +CONFIG_NET_UDP=y +CONFIG_NET_TCP=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_LOG=y +CONFIG_NET_SLIP_TAP=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_INIT_STACKS=y +CONFIG_PRINTK=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_NBUF_RX_COUNT=16 +CONFIG_NET_NBUF_TX_COUNT=16 +CONFIG_NET_NBUF_DATA_COUNT=40 +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 +CONFIG_NET_MAX_CONTEXTS=16 + +CONFIG_NET_SHELL=y + +CONFIG_NET_SAMPLES_IP_ADDRESSES=y +CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2" +CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.0.2.2" diff --git a/samples/net/http_server/README.rst b/samples/net/http_server/README.rst index 27b77829c60..792bbdaa1e6 100644 --- a/samples/net/http_server/README.rst +++ b/samples/net/http_server/README.rst @@ -109,7 +109,6 @@ Refer to the board documentation in Zephyr, :ref:`frdm_k64f`, for more information about this board and how to access the FRDM serial console under other operating systems. - Sample Output ============= @@ -223,6 +222,60 @@ and this is the HTML message that wget will save:

404 Not Found

+HTTPS Server +============ + +The sample code also includes a HTTPS (HTTP over TLS) server example +running side by side with the HTTP server, this server runs on qemu. +In order to compile and run the code execute: + +.. code-block:: console + + make BOARD=qemu_x86 run + +The sample code supports only one hard-coded valid URL (index.html) and +will return 404 code for other requests. + +Sample Output +============= + +The app will show the following on the screen: + +.. code-block:: console + + Zephyr HTTP Server + Address: 192.0.2.1, port: 80 + Zephyr HTTPS Server + Address: 192.0.2.1, port: 443 + failed + ! mbedtls_ssl_handshake returned -29312 + +Now execute the following command on a different terminal window + +.. code-block:: console + + wget https://192.0.2.1 --no-check-certificate + +This will be shown on the screen + +.. code-block:: console + + Connecting to 192.0.2.1:443... connected. + WARNING: cannot verify 192.0.2.1's certificate + Unable to locally verify the issuer's authority. + HTTP request sent, awaiting response... 200 OK + Length: unspecified [text/html] + Saving to: ‘index.html’ + + index.html [ <=> ] + +The inspection of the file index.html will show + +.. code-block:: console + +

Zephyr TLS Test Server

+

Successful connection

+ Known Issues and Limitations ============================ @@ -230,3 +283,5 @@ Known Issues and Limitations chunk transfer mode. - Clients must close the connection to allow the HTTP server to release the network context and accept another connection. +- The use of mbedTLS and IPv6 takes more than the available ram for the + emulation platform, so only IPv4 works for now in QEMU. diff --git a/samples/net/http_server/prj_qemu_x86.conf b/samples/net/http_server/prj_qemu_x86.conf new file mode 100644 index 00000000000..88ba68d55cd --- /dev/null +++ b/samples/net/http_server/prj_qemu_x86.conf @@ -0,0 +1,34 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TCP=y +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_NET_LOG=y +CONFIG_NET_SLIP_TAP=y +CONFIG_INIT_STACKS=y + +CONFIG_NET_NBUF_RX_COUNT=16 +CONFIG_NET_NBUF_TX_COUNT=16 +CONFIG_NET_NBUF_DATA_COUNT=16 + +CONFIG_NET_IPV6_RA_RDNSS=y +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=2 + +CONFIG_STDOUT_CONSOLE=y + +CONFIG_HTTP_PARSER=y + +# Enable IPv6 support +CONFIG_NET_IPV6=n +# Enable IPv4 support +CONFIG_NET_IPV4=y + +CONFIG_NET_SAMPLES_IP_ADDRESSES=y +CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.0.2.1" + +CONFIG_NET_MAX_CONTEXTS=16 + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h" diff --git a/samples/net/http_server/src/Makefile b/samples/net/http_server/src/Makefile index 11d9be11798..5219783b92f 100644 --- a/samples/net/http_server/src/Makefile +++ b/samples/net/http_server/src/Makefile @@ -8,3 +8,8 @@ obj-y += main.o obj-y += http_utils.o obj-y += http_server.o obj-y += http_write_utils.o +ifdef CONFIG_MBEDTLS +obj-y += https_server.o ssl_utils.o +endif + + diff --git a/samples/net/http_server/src/config.h b/samples/net/http_server/src/config.h index 672b663633a..054a4c4e3bc 100644 --- a/samples/net/http_server/src/config.h +++ b/samples/net/http_server/src/config.h @@ -25,4 +25,8 @@ #define APP_SLEEP_MSECS 500 +#ifdef CONFIG_MBEDTLS +#define SERVER_PORT 443 +#endif + #endif diff --git a/samples/net/http_server/src/http_server.c b/samples/net/http_server/src/http_server.c index 3355a4ce037..a94c59ede6b 100644 --- a/samples/net/http_server/src/http_server.c +++ b/samples/net/http_server/src/http_server.c @@ -21,6 +21,32 @@ NET_BUF_POOL_DEFINE(http_msg_pool, HTTP_BUF_CTR, HTTP_BUF_SIZE, 0, NULL); +void http_accept_cb(struct net_context *net_ctx, struct sockaddr *addr, + socklen_t addr_len, int status, void *data) +{ + struct http_server_ctx *http_ctx = NULL; + + ARG_UNUSED(addr_len); + ARG_UNUSED(data); + + if (status != 0) { + net_context_put(net_ctx); + return; + } + + print_client_banner(addr); + + http_ctx = http_ctx_get(); + if (!http_ctx) { + net_context_put(net_ctx); + return; + } + + http_ctx_set(http_ctx, net_ctx); + + net_context_recv(net_ctx, http_rx_tx, K_NO_WAIT, http_ctx); +} + /** * @brief http_ctx_release Releases an HTTP context * @return 0, future versions may return error codes diff --git a/samples/net/http_server/src/http_server.h b/samples/net/http_server/src/http_server.h index 45751c56fcf..5e00279d33f 100644 --- a/samples/net/http_server/src/http_server.h +++ b/samples/net/http_server/src/http_server.h @@ -9,6 +9,10 @@ #include +/* Callback executed when a new connection is accepted */ +void http_accept_cb(struct net_context *net_ctx, struct sockaddr *addr, + socklen_t addr_len, int status, void *data); + /** * @brief http_rx_tx Reads the HTTP request from the `rx` buffer * and writes an HTTP 1.1 200 OK response with client diff --git a/samples/net/http_server/src/https_server.c b/samples/net/http_server/src/https_server.c new file mode 100644 index 00000000000..6173c7ec21a --- /dev/null +++ b/samples/net/http_server/src/https_server.c @@ -0,0 +1,406 @@ +/* Minimal TLS server. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * SPDX-License-Identifier: Apache-2.0 + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#include +#include + +#include +#include + +#if !defined(CONFIG_MBEDTLS_CFG_FILE) +#include "mbedtls/config.h" +#else +#include CONFIG_MBEDTLS_CFG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_time_t time_t +#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS +#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE +#endif + +#include +#include +#include +#include "config.h" +#include "ssl_utils.h" +#include "test_certs.h" + +#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/ssl.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" + +#if defined(MBEDTLS_DEBUG_C) +#include "mbedtls/debug.h" +#define DEBUG_THRESHOLD 0 +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#include "mbedtls/memory_buffer_alloc.h" +static unsigned char heap[12000]; +#endif + +/* + * Hardcoded values for server host and port + */ + +static const char *pers = "tls_server"; + +#if defined(CONFIG_NET_IPV6) +static struct in6_addr server_addr; +#else +static struct in_addr server_addr; +#endif + +struct parsed_url { + const char *url; + uint16_t url_len; +}; + +#define HTTP_RESPONSE \ + "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ + "

Zephyr TLS Test Server

\r\n" \ + "

Successful connection

\r\n" + +#define HTTP_NOT_FOUND \ + "HTTP/1.0 404 NOT FOUND\r\nContent-Type: text/html\r\n\r\n" \ + "

Zephyr TLS page not found

\r\n" \ + "

Successful connection

\r\n" + +static void my_debug(void *ctx, int level, + const char *file, int line, const char *str) +{ + const char *p, *basename; + + ARG_UNUSED(ctx); + + /* Extract basename from file */ + for (p = basename = file; *p != '\0'; p++) { + if (*p == '/' || *p == '\\') { + basename = p + 1; + } + + } + + mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str); +} + +static int entropy_source(void *data, unsigned char *output, size_t len, + size_t *olen) +{ + uint32_t seed; + + ARG_UNUSED(data); + + seed = sys_rand32_get(); + + if (len > sizeof(seed)) { + len = sizeof(seed); + } + + memcpy(output, &seed, len); + + *olen = len; + return 0; +} + +static +int on_url(struct http_parser *parser, const char *at, size_t length) +{ + struct parsed_url *req = (struct parsed_url *)parser->data; + + req->url = at; + req->url_len = length; + + return 0; +} + +static unsigned char payload[256]; + +void https_server(void) +{ + struct ssl_context ctx; + struct parsed_url request; + int ret, len = 0; + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_x509_crt srvcert; + mbedtls_pk_context pkey; + + mbedtls_platform_set_printf(printk); + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) + mbedtls_memory_buffer_alloc_init(heap, sizeof(heap)); +#endif + +#if defined(MBEDTLS_DEBUG_C) + mbedtls_debug_set_threshold(DEBUG_THRESHOLD); + mbedtls_ssl_conf_dbg(&conf, my_debug, NULL); +#endif + mbedtls_x509_crt_init(&srvcert); + mbedtls_pk_init(&pkey); + mbedtls_ssl_init(&ssl); + mbedtls_ssl_config_init(&conf); + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + /* + * 1. Load the certificates and private RSA key + */ + + ret = mbedtls_x509_crt_parse(&srvcert, rsa_example_cert_der, + rsa_example_cert_der_len); + if (ret != 0) { + mbedtls_printf(" failed\n !" + " mbedtls_x509_crt_parse returned %d\n\n", ret); + goto exit; + } + + ret = mbedtls_pk_parse_key(&pkey, rsa_example_keypair_der, + rsa_example_keypair_der_len, NULL, 0); + if (ret != 0) { + mbedtls_printf(" failed\n !" + " mbedtls_pk_parse_key returned %d\n\n", ret); + goto exit; + } + + /* + * 3. Seed the RNG + */ + + mbedtls_entropy_add_source(&entropy, entropy_source, NULL, + MBEDTLS_ENTROPY_MAX_GATHER, + MBEDTLS_ENTROPY_SOURCE_STRONG); + + ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char *)pers, strlen(pers)); + if (ret != 0) { + mbedtls_printf(" failed\n !" + " mbedtls_ctr_drbg_seed returned %d\n", ret); + goto exit; + } + + /* + * 4. Setup stuff + */ + ret = mbedtls_ssl_config_defaults(&conf, + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { + mbedtls_printf(" failed\n !" + " mbedtls_ssl_config_defaults returned %d\n\n", + ret); + goto exit; + } + + mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); + mbedtls_ssl_conf_dbg(&conf, my_debug, NULL); + + mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL); + ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey); + if (ret != 0) { + mbedtls_printf(" failed\n !" + " mbedtls_ssl_conf_own_cert returned %d\n\n", + ret); + goto exit; + } + + ret = mbedtls_ssl_setup(&ssl, &conf); + if (ret != 0) { + mbedtls_printf(" failed\n !" + " mbedtls_ssl_setup returned %d\n\n", ret); + goto exit; + } + + /* + * 3. Wait until a client connects + */ + ret = ssl_init(&ctx, &server_addr); + if (ret != 0) { + mbedtls_printf(" failed\n ! ssl_init returned %d\n\n", ret); + goto exit; + + } + + /* + * 4. Prepare http parser + */ + http_parser_init(&ctx.parser, HTTP_REQUEST); + http_parser_settings_init(&ctx.parser_settings); + ctx.parser.data = &request; + ctx.parser_settings.on_url = on_url; + + mbedtls_printf("Zephyr HTTPS Server\n"); + mbedtls_printf("Address: %s, port: %d\n", ZEPHYR_ADDR, SERVER_PORT); +reset: + mbedtls_ssl_session_reset(&ssl); + mbedtls_ssl_set_bio(&ssl, &ctx, ssl_tx, ssl_rx, NULL); + /* + * 5. Handshake + */ + do { + ret = mbedtls_ssl_handshake(&ssl); + if (ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + if (ret < 0) { + mbedtls_printf(" failed\n !" + " mbedtls_ssl_handshake returned %d\n\n", + ret); + goto reset; + } + } + } while (ret != 0); + + /* + * 6. Read the HTTPS Request + */ + mbedtls_printf("Read HTTPS request\n"); + do { + len = sizeof(payload) - 1; + memset(payload, 0, sizeof(payload)); + ret = mbedtls_ssl_read(&ssl, payload, len); + + if (ret == MBEDTLS_ERR_SSL_WANT_READ || + ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + continue; + } + + if (ret <= 0) { + switch (ret) { + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + mbedtls_printf(" connection was" + " closed gracefully\n"); + goto close; + + case MBEDTLS_ERR_NET_CONN_RESET: + mbedtls_printf(" connection was" + " reset by peer\n"); + break; + + default: + mbedtls_printf + (" mbedtls_ssl_read returned -0x%x\n", + -ret); + break; + } + + break; + } + + len = ret; + ret = http_parser_execute(&ctx.parser, &ctx.parser_settings, + payload, len); + if (ret < 0) { + } + } while (ret < 0); + + /* + * 7. Write the Response + */ + mbedtls_printf("Write HTTPS response\n"); + + if (!strncmp("/index.html", request.url, request.url_len)) { + len = snprintf((char *)payload, sizeof(payload), + HTTP_RESPONSE); + } else { + + len = snprintf((char *)payload, sizeof(payload), + HTTP_NOT_FOUND); + } + + do { + ret = mbedtls_ssl_write(&ssl, payload, len); + if (ret == MBEDTLS_ERR_NET_CONN_RESET) { + mbedtls_printf(" failed\n !" + " peer closed the connection\n"); + goto reset; + } + + if (ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + if (ret < 0) { + mbedtls_printf(" failed\n !" + " mbedtls_ssl_write" + " returned %d\n", ret); + goto exit; + } + } + } while (ret <= 0); + +close: + + mbedtls_ssl_close_notify(&ssl); + ret = 0; + goto reset; + +exit: +#ifdef MBEDTLS_ERROR_C + if (ret != 0) { + mbedtls_strerror(ret, payload, 100); + mbedtls_printf("Last error was: %d - %s\n", ret, payload); + } +#endif + + mbedtls_ssl_free(&ssl); + mbedtls_ssl_config_free(&conf); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); +} + +#define STACK_SIZE 8192 +uint8_t stack[STACK_SIZE]; + +static inline int init_app(void) +{ +#if defined(CONFIG_NET_IPV6) + if (net_addr_pton(AF_INET6, ZEPHYR_ADDR, &server_addr) < 0) { + mbedtls_printf("Invalid IPv6 address %s", ZEPHYR_ADDR); + } + + if (!net_if_ipv6_addr_add(net_if_get_default(), &server_addr, + NET_ADDR_MANUAL, 0)) { + return -EIO; + } +#else + if (net_addr_pton(AF_INET, ZEPHYR_ADDR, &server_addr) < 0) { + mbedtls_printf("Invalid IPv4 address %s", ZEPHYR_ADDR); + } + + if (!net_if_ipv4_addr_add(net_if_get_default(), &server_addr, + NET_ADDR_MANUAL, 0)) { + return -EIO; + } +#endif + + return 0; +} + +void https_server_start(void) +{ + if (init_app() != 0) { + printk("Cannot initialize network\n"); + return; + } + + k_thread_spawn(stack, STACK_SIZE, (k_thread_entry_t) https_server, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); + +} diff --git a/samples/net/http_server/src/main.c b/samples/net/http_server/src/main.c index c01d789bb07..d71f897ad89 100644 --- a/samples/net/http_server/src/main.c +++ b/samples/net/http_server/src/main.c @@ -15,82 +15,53 @@ #include "http_write_utils.h" #include "config.h" -static void network_setup(void); +/* Sets the network parameters */ +static +int network_setup(struct net_context **net_ctx, net_tcp_accept_cb_t accept_cb, + const char *addr, uint16_t port); + +#if defined(CONFIG_MBEDTLS) +#include "ssl_utils.h" +#endif void main(void) { + struct net_context *net_ctx = NULL; + http_ctx_init(); http_url_default_handler(http_write_soft_404_not_found); http_url_add("/headers", HTTP_URL_STANDARD, http_write_header_fields); http_url_add("/index.html", HTTP_URL_STANDARD, http_write_it_works); - network_setup(); + network_setup(&net_ctx, http_accept_cb, ZEPHYR_ADDR, ZEPHYR_PORT); } -/** - * @brief connection_cb Callback executed when a connection is accepted - * @param ctx Network context - * @param addr Client's address - * @param addr_len Address length - * @param status Status code, 0 on success, < 0 otherwise - * @param data User-provided data - */ -void connection_cb(struct net_context *net_ctx, struct sockaddr *addr, - socklen_t addr_len, int status, void *data) +static +int network_setup(struct net_context **net_ctx, net_tcp_accept_cb_t accept_cb, + const char *addr, uint16_t port) { - struct http_server_ctx *http_ctx = NULL; - - ARG_UNUSED(addr_len); - ARG_UNUSED(data); - - if (status != 0) { - printk("Status code: %d\n", status); - net_context_put(net_ctx); - return; - } - - print_client_banner(addr); - - http_ctx = http_ctx_get(); - if (!http_ctx) { - printk("Unable to get free HTTP context\n"); - net_context_put(net_ctx); - return; - } - - http_ctx_set(http_ctx, net_ctx); - - net_context_recv(net_ctx, http_rx_tx, 0, http_ctx); -} - -/** - * @brief network_setup This routine configures the HTTP server. - * It puts the application in listening mode and - * installs the accept connection callback. - */ -static void network_setup(void) -{ - struct net_context *ctx = NULL; struct sockaddr local_sock; void *ptr; int rc; + *net_ctx = NULL; + #ifdef CONFIG_NET_IPV6 - net_sin6(&local_sock)->sin6_port = htons(ZEPHYR_PORT); - sock_addr.family = AF_INET6; + net_sin6(&local_sock)->sin6_port = htons(port); + local_sock.family = AF_INET6; ptr = &(net_sin6(&local_sock)->sin6_addr); - rc = net_addr_pton(AF_INET6, ZEPHYR_ADDR, ptr); + rc = net_addr_pton(AF_INET6, addr, ptr); #else - net_sin(&local_sock)->sin_port = htons(ZEPHYR_PORT); + net_sin(&local_sock)->sin_port = htons(port); local_sock.family = AF_INET; ptr = &(net_sin(&local_sock)->sin_addr); - rc = net_addr_pton(AF_INET, ZEPHYR_ADDR, ptr); + rc = net_addr_pton(AF_INET, addr, ptr); #endif if (rc) { - printk("Invalid IP address/Port: %s, %d\n", - ZEPHYR_ADDR, ZEPHYR_PORT); + printk("Invalid IP address/Port: %s, %d\n", addr, port); + return rc; } #ifdef CONFIG_NET_IPV6 @@ -102,41 +73,46 @@ static void network_setup(void) &net_sin(&local_sock)->sin_addr, NET_ADDR_MANUAL, 0); #endif - print_server_banner(&local_sock); #if defined(CONFIG_NET_IPV6) - rc = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &ctx); + rc = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, net_ctx); #else - rc = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx); + rc = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, net_ctx); #endif if (rc != 0) { printk("net_context_get error\n"); - return; + return rc; } - rc = net_context_bind(ctx, (const struct sockaddr *)&local_sock, + rc = net_context_bind(*net_ctx, (const struct sockaddr *)&local_sock, sizeof(local_sock)); if (rc != 0) { printk("net_context_bind error\n"); goto lb_error; } - rc = net_context_listen(ctx, 0); + rc = net_context_listen(*net_ctx, 0); if (rc != 0) { - printk("[%s:%d] net_context_listen %d, <%s>\n", - __func__, __LINE__, rc, RC_STR(rc)); + printk("net_context_listen error\n"); goto lb_error; } - rc = net_context_accept(ctx, connection_cb, 0, NULL); + rc = net_context_accept(*net_ctx, accept_cb, 0, NULL); if (rc != 0) { - printk("[%s:%d] net_context_accept %d, <%s>\n", - __func__, __LINE__, rc, RC_STR(rc)); + printk("net_context_accept error\n"); goto lb_error; } - return; + print_server_banner(&local_sock); + +#if defined(CONFIG_MBEDTLS) + https_server_start(); +#endif + return 0; lb_error: - net_context_put(ctx); + net_context_put(*net_ctx); + *net_ctx = NULL; + + return rc; } diff --git a/samples/net/http_server/src/ssl_utils.c b/samples/net/http_server/src/ssl_utils.c new file mode 100644 index 00000000000..ac75aadd0e1 --- /dev/null +++ b/samples/net/http_server/src/ssl_utils.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_MBEDTLS_CFG_FILE) +#include "mbedtls/config.h" +#else +#include CONFIG_MBEDTLS_CFG_FILE +#endif + +#include "mbedtls/ssl.h" + +#include "config.h" +#include "ssl_utils.h" + +#define RX_FIFO_DEPTH 4 + +K_MEM_POOL_DEFINE(rx_pkts, 4, 64, RX_FIFO_DEPTH, 4); + +static void ssl_received(struct net_context *context, + struct net_buf *buf, int status, void *user_data) +{ + struct ssl_context *ctx = user_data; + struct rx_fifo_block *rx_data = NULL; + struct k_mem_block block; + + ARG_UNUSED(context); + ARG_UNUSED(status); + + if (!net_nbuf_appdatalen(buf)) { + net_nbuf_unref(buf); + return; + } + + k_mem_pool_alloc(&rx_pkts, &block, + sizeof(struct rx_fifo_block), K_FOREVER); + rx_data = block.data; + rx_data->buf = buf; + + /* For freeing memory later */ + memcpy(&rx_data->block, &block, sizeof(struct k_mem_block)); + k_fifo_put(&ctx->rx_fifo, (void *)rx_data); +} + +static inline void ssl_sent(struct net_context *context, + int status, void *token, void *user_data) +{ + struct ssl_context *ctx = user_data; + + k_sem_give(&ctx->tx_sem); +} + +int ssl_tx(void *context, const unsigned char *buf, size_t size) +{ + struct ssl_context *ctx = context; + struct net_context *net_ctx; + struct net_buf *send_buf; + + int rc, len; + + net_ctx = ctx->net_ctx; + + send_buf = net_nbuf_get_tx(net_ctx, K_NO_WAIT); + if (!send_buf) { + return MBEDTLS_ERR_SSL_ALLOC_FAILED; + } + + rc = net_nbuf_append(send_buf, size, (uint8_t *) buf, K_FOREVER); + if (!rc) { + net_nbuf_unref(send_buf); + return MBEDTLS_ERR_SSL_INTERNAL_ERROR; + } + + len = net_buf_frags_len(send_buf); + + rc = net_context_send(send_buf, ssl_sent, K_NO_WAIT, NULL, ctx); + + if (rc < 0) { + net_nbuf_unref(send_buf); + return MBEDTLS_ERR_SSL_INTERNAL_ERROR; + } + + k_sem_take(&ctx->tx_sem, K_FOREVER); + return len; +} + +int ssl_rx(void *context, unsigned char *buf, size_t size) +{ + struct ssl_context *ctx = context; + uint16_t read_bytes; + struct rx_fifo_block *rx_data; + uint8_t *ptr; + int pos; + int len; + int rc = 0; + + if (ctx->frag == NULL) { + rx_data = k_fifo_get(&ctx->rx_fifo, K_FOREVER); + ctx->rx_nbuf = rx_data->buf; + k_mem_pool_free(&rx_data->block); + + read_bytes = net_nbuf_appdatalen(ctx->rx_nbuf); + + ctx->remaining = read_bytes; + ctx->frag = ctx->rx_nbuf->frags; + ptr = net_nbuf_appdata(ctx->rx_nbuf); + + len = ptr - ctx->frag->data; + net_buf_pull(ctx->frag, len); + } else { + read_bytes = ctx->remaining; + ptr = ctx->frag->data; + } + + len = ctx->frag->len; + pos = 0; + if (read_bytes > size) { + while (ctx->frag) { + read_bytes = len < (size - pos) ? len : (size - pos); + memcpy(buf + pos, ptr, read_bytes); + pos += read_bytes; + if (pos < size) { + ctx->frag = ctx->frag->frags; + ptr = ctx->frag->data; + len = ctx->frag->len; + } else { + if (read_bytes == len) { + ctx->frag = ctx->frag->frags; + } else { + net_buf_pull(ctx->frag, read_bytes); + } + + ctx->remaining -= size; + return size; + } + } + } else { + while (ctx->frag) { + memcpy(buf + pos, ptr, len); + pos += len; + ctx->frag = ctx->frag->frags; + if (!ctx->frag) { + break; + } + + ptr = ctx->frag->data; + len = ctx->frag->len; + } + + net_nbuf_unref(ctx->rx_nbuf); + ctx->rx_nbuf = NULL; + ctx->frag = NULL; + ctx->remaining = 0; + + if (read_bytes != pos) { + return -EIO; + } + + rc = read_bytes; + } + + return rc; +} + +static void ssl_accepted(struct net_context *context, + struct sockaddr *addr, + socklen_t addrlen, int error, void *user_data) +{ + int ret; + struct ssl_context *ctx = user_data; + + ctx->net_ctx = context; + ret = net_context_recv(context, ssl_received, 0, user_data); + if (ret < 0) { + printk("Cannot receive TCP packet (family %d)", + net_context_get_family(context)); + } + +} + +#if defined(CONFIG_NET_IPV6) +int ssl_init(struct ssl_context *ctx, void *addr) +{ + struct net_context *tcp_ctx = { 0 }; + struct sockaddr_in6 my_addr = { 0 }; + struct in6_addr *server_addr = addr; + int rc; + + k_sem_init(&ctx->tx_sem, 0, UINT_MAX); + k_fifo_init(&ctx->rx_fifo); + + my_mcast_addr.sin6_family = AF_INET6; + + net_ipaddr_copy(&my_addr.sin6_addr, server_addr); + my_addr.sin6_family = AF_INET6; + my_addr.sin6_port = htons(SERVER_PORT); + + rc = net_context_get(AF_INET6, SOCK_STREAM, IPPROTO_TCP, &tcp_ctx); + if (rc < 0) { + printk("Cannot get network context for IPv6 TCP (%d)", rc); + return -EIO; + } + + rc = net_context_bind(tcp_ctx, (struct sockaddr *)&my_addr, + sizeof(struct sockaddr_in6)); + if (rc < 0) { + printk("Cannot bind IPv6 TCP port %d (%d)", SERVER_PORT, rc); + goto error; + } + + ctx->rx_nbuf = NULL; + ctx->remaining = 0; + ctx->net_ctx = tcp_ctx; + + rc = net_context_listen(ctx->net_ctx, 0); + if (rc < 0) { + printk("Cannot listen IPv6 TCP (%d)", rc); + return -EIO; + } + + rc = net_context_accept(ctx->net_ctx, ssl_accepted, 0, ctx); + if (rc < 0) { + printk("Cannot accept IPv4 (%d)", rc); + return -EIO; + } + + return 0; + +error: + net_context_put(tcp_ctx); + return -EINVAL; +} + +#else +int ssl_init(struct ssl_context *ctx, void *addr) +{ + struct net_context *tcp_ctx = { 0 }; + struct sockaddr_in my_addr4 = { 0 }; + struct in_addr *server_addr = addr; + int rc; + + k_sem_init(&ctx->tx_sem, 0, UINT_MAX); + k_fifo_init(&ctx->rx_fifo); + + net_ipaddr_copy(&my_addr4.sin_addr, server_addr); + my_addr4.sin_family = AF_INET; + my_addr4.sin_port = htons(SERVER_PORT); + + rc = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &tcp_ctx); + if (rc < 0) { + printk("Cannot get network context for IPv4 TCP (%d)", rc); + return -EIO; + } + + rc = net_context_bind(tcp_ctx, (struct sockaddr *)&my_addr4, + sizeof(struct sockaddr_in)); + if (rc < 0) { + printk("Cannot bind IPv4 TCP port %d (%d)", SERVER_PORT, rc); + goto error; + } + + ctx->rx_nbuf = NULL; + ctx->remaining = 0; + ctx->net_ctx = tcp_ctx; + + rc = net_context_listen(ctx->net_ctx, 0); + if (rc < 0) { + printk("Cannot listen IPv4 (%d)", rc); + return -EIO; + } + + rc = net_context_accept(ctx->net_ctx, ssl_accepted, 0, ctx); + if (rc < 0) { + printk("Cannot accept IPv4 (%d)", rc); + return -EIO; + } + + return 0; + +error: + net_context_put(tcp_ctx); + return -EINVAL; +} +#endif diff --git a/samples/net/http_server/src/ssl_utils.h b/samples/net/http_server/src/ssl_utils.h new file mode 100644 index 00000000000..a0ef50eff1f --- /dev/null +++ b/samples/net/http_server/src/ssl_utils.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SSL_UTILS_H_ +#define _SSL_UTILS_H_ + +#include +#include + +struct rx_fifo_block { + sys_snode_t snode; + struct k_mem_block block; + struct net_buf *buf; +}; + +struct ssl_context { + struct net_context *net_ctx; + struct net_buf *rx_nbuf; + struct net_buf *frag; + struct k_sem tx_sem; + struct k_fifo rx_fifo; + struct http_parser_settings parser_settings; + struct http_parser parser; + + int remaining; +}; + +int ssl_init(struct ssl_context *ctx, void *addr); +int ssl_tx(void *ctx, const unsigned char *buf, size_t size); +int ssl_rx(void *ctx, unsigned char *buf, size_t size); + +void https_server_start(void); + +#endif diff --git a/samples/net/http_server/src/test_certs.h b/samples/net/http_server/src/test_certs.h new file mode 100644 index 00000000000..5b6326110dc --- /dev/null +++ b/samples/net/http_server/src/test_certs.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __TEST_CERTS_H__ +#define __TEST_CERTS_H__ + +static const unsigned char rsa_example_keypair_der[] = { + 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0x9b, 0xfc, + 0x66, 0x90, 0x79, 0x84, 0x42, 0xbb, 0xab, 0x13, 0xfd, 0x2b, 0x7b, 0xf8, + 0xde, 0x15, 0x12, 0xe5, 0xf1, 0x93, 0xe3, 0x06, 0x8a, 0x7b, 0xb8, 0xb1, + 0xe1, 0x9e, 0x26, 0xbb, 0x95, 0x01, 0xbf, 0xe7, 0x30, 0xed, 0x64, 0x85, + 0x02, 0xdd, 0x15, 0x69, 0xa8, 0x34, 0xb0, 0x06, 0xec, 0x3f, 0x35, 0x3c, + 0x1e, 0x1b, 0x2b, 0x8f, 0xfa, 0x8f, 0x00, 0x1b, 0xdf, 0x07, 0xc6, 0xac, + 0x53, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x1b, 0x4a, 0xf7, + 0x7b, 0x31, 0xf7, 0xe5, 0x61, 0x46, 0xd6, 0xd1, 0x86, 0x69, 0x43, 0xab, + 0x40, 0x0e, 0xb5, 0x73, 0x26, 0x88, 0x23, 0x9d, 0xd9, 0x76, 0x00, 0x91, + 0xd4, 0x85, 0x3c, 0x6f, 0x1e, 0xc0, 0x51, 0xeb, 0xe6, 0x90, 0x5b, 0x41, + 0x7f, 0xe6, 0xaa, 0x31, 0x6b, 0xac, 0x59, 0x53, 0x96, 0x26, 0xf1, 0xae, + 0xda, 0xbe, 0x55, 0xa4, 0x75, 0x40, 0x22, 0x5f, 0x27, 0x17, 0xa0, 0xd2, + 0x91, 0x02, 0x21, 0x00, 0xc8, 0xc4, 0x27, 0x7c, 0xd5, 0x61, 0xad, 0xbf, + 0x32, 0x8e, 0x1e, 0xcb, 0xe8, 0x94, 0xf4, 0x9f, 0x55, 0x77, 0xe5, 0xa8, + 0xc9, 0x70, 0xd0, 0x0f, 0x81, 0x04, 0xb7, 0x09, 0xb2, 0x1b, 0x53, 0xe9, + 0x02, 0x21, 0x00, 0xc6, 0xe6, 0x65, 0xbe, 0x10, 0xc8, 0x6d, 0xb7, 0x1e, + 0xee, 0x8e, 0x41, 0xbc, 0xe8, 0x67, 0x09, 0x9d, 0x8d, 0xee, 0x46, 0x1b, + 0xd5, 0x90, 0xb9, 0xee, 0x0d, 0xc5, 0xf9, 0xc6, 0xc9, 0xc9, 0x6f, 0x02, + 0x21, 0x00, 0x9b, 0xb0, 0x31, 0x87, 0x06, 0xda, 0x36, 0xa8, 0x9c, 0x85, + 0xc5, 0xb0, 0x0e, 0xee, 0xe4, 0x3c, 0x63, 0x45, 0x15, 0x1d, 0xad, 0x09, + 0x04, 0xef, 0xe0, 0xf7, 0x4d, 0x12, 0x01, 0xc2, 0x5b, 0x71, 0x02, 0x20, + 0x46, 0xd1, 0x25, 0x8c, 0x84, 0xa1, 0x38, 0x1f, 0x29, 0x0e, 0x3a, 0xec, + 0x40, 0xfc, 0x66, 0x23, 0x50, 0x4b, 0x86, 0x78, 0xc3, 0xd4, 0x48, 0x51, + 0x4a, 0xe6, 0xf0, 0x84, 0x3c, 0x39, 0x00, 0x55, 0x02, 0x21, 0x00, 0x8d, + 0x03, 0x6e, 0x29, 0x0e, 0xd7, 0x4e, 0x1f, 0x27, 0x70, 0xb5, 0x20, 0x79, + 0xfb, 0x31, 0x6a, 0x14, 0xb7, 0xe6, 0x55, 0x9a, 0x65, 0x40, 0xcf, 0xe0, + 0xe6, 0x46, 0xf8, 0xb2, 0x8e, 0xf4, 0x63, 0x0a +}; + +static const unsigned int rsa_example_keypair_der_len = 320; + +static const unsigned char rsa_example_cert_der[] = { + 0x30, 0x82, 0x02, 0x12, 0x30, 0x82, 0x01, 0x7b, 0x02, 0x02, 0x0d, 0xfa, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x30, 0x81, 0x9b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x13, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x43, 0x68, + 0x75, 0x6f, 0x2d, 0x6b, 0x75, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x08, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x34, 0x44, 0x44, + 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0f, 0x57, + 0x65, 0x62, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0f, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x34, 0x44, 0x44, 0x20, 0x57, 0x65, + 0x62, 0x20, 0x43, 0x41, 0x31, 0x23, 0x30, 0x21, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x14, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x40, 0x66, 0x72, 0x61, 0x6e, 0x6b, 0x34, 0x64, + 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, + 0x38, 0x32, 0x32, 0x30, 0x35, 0x32, 0x36, 0x35, 0x34, 0x5a, 0x17, 0x0d, + 0x31, 0x37, 0x30, 0x38, 0x32, 0x31, 0x30, 0x35, 0x32, 0x36, 0x35, 0x34, + 0x5a, 0x30, 0x4a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x46, 0x72, 0x61, 0x6e, 0x6b, + 0x34, 0x44, 0x44, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, + 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9b, 0xfc, 0x66, 0x90, 0x79, 0x84, + 0x42, 0xbb, 0xab, 0x13, 0xfd, 0x2b, 0x7b, 0xf8, 0xde, 0x15, 0x12, 0xe5, + 0xf1, 0x93, 0xe3, 0x06, 0x8a, 0x7b, 0xb8, 0xb1, 0xe1, 0x9e, 0x26, 0xbb, + 0x95, 0x01, 0xbf, 0xe7, 0x30, 0xed, 0x64, 0x85, 0x02, 0xdd, 0x15, 0x69, + 0xa8, 0x34, 0xb0, 0x06, 0xec, 0x3f, 0x35, 0x3c, 0x1e, 0x1b, 0x2b, 0x8f, + 0xfa, 0x8f, 0x00, 0x1b, 0xdf, 0x07, 0xc6, 0xac, 0x53, 0x07, 0x02, 0x03, + 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x14, 0xb6, + 0x4c, 0xbb, 0x81, 0x79, 0x33, 0xe6, 0x71, 0xa4, 0xda, 0x51, 0x6f, 0xcb, + 0x08, 0x1d, 0x8d, 0x60, 0xec, 0xbc, 0x18, 0xc7, 0x73, 0x47, 0x59, 0xb1, + 0xf2, 0x20, 0x48, 0xbb, 0x61, 0xfa, 0xfc, 0x4d, 0xad, 0x89, 0x8d, 0xd1, + 0x21, 0xeb, 0xd5, 0xd8, 0xe5, 0xba, 0xd6, 0xa6, 0x36, 0xfd, 0x74, 0x50, + 0x83, 0xb6, 0x0f, 0xc7, 0x1d, 0xdf, 0x7d, 0xe5, 0x2e, 0x81, 0x7f, 0x45, + 0xe0, 0x9f, 0xe2, 0x3e, 0x79, 0xee, 0xd7, 0x30, 0x31, 0xc7, 0x20, 0x72, + 0xd9, 0x58, 0x2e, 0x2a, 0xfe, 0x12, 0x5a, 0x34, 0x45, 0xa1, 0x19, 0x08, + 0x7c, 0x89, 0x47, 0x5f, 0x4a, 0x95, 0xbe, 0x23, 0x21, 0x4a, 0x53, 0x72, + 0xda, 0x2a, 0x05, 0x2f, 0x2e, 0xc9, 0x70, 0xf6, 0x5b, 0xfa, 0xfd, 0xdf, + 0xb4, 0x31, 0xb2, 0xc1, 0x4a, 0x9c, 0x06, 0x25, 0x43, 0xa1, 0xe6, 0xb4, + 0x1e, 0x7f, 0x86, 0x9b, 0x16, 0x40, 0x0a +}; + +static const unsigned int rsa_example_cert_der_len = 535; + +#endif diff --git a/samples/net/http_server/testcase.ini b/samples/net/http_server/testcase.ini index 1c14f3d7052..6b7a95b312c 100644 --- a/samples/net/http_server/testcase.ini +++ b/samples/net/http_server/testcase.ini @@ -1,4 +1,4 @@ [test] tags = net http build_only = true -platform_whitelist = frdm_k64f +platform_whitelist = frdm_k64f qemu_x86 diff --git a/samples/net/leds_demo/prj_802154.conf b/samples/net/leds_demo/prj_802154.conf index 1efd33265ca..63080d3d705 100644 --- a/samples/net/leds_demo/prj_802154.conf +++ b/samples/net/leds_demo/prj_802154.conf @@ -6,7 +6,6 @@ CONFIG_NET_L2_IEEE802154_ORFD_CHANNEL=20 CONFIG_NET_L2_IEEE802154_FRAGMENT=y CONFIG_NET_LOG=y CONFIG_NET_UDP=y -CONFIG_NET_YAIP=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_IEEE802154_CC2520=y CONFIG_ZOAP=y diff --git a/samples/net/mqtt_publisher/prj_96b_nitrogen.conf b/samples/net/mqtt_publisher/prj_96b_nitrogen.conf new file mode 100644 index 00000000000..2268eff7330 --- /dev/null +++ b/samples/net/mqtt_publisher/prj_96b_nitrogen.conf @@ -0,0 +1,65 @@ +CONFIG_INIT_STACKS=y +CONFIG_NETWORKING=y + +CONFIG_NET_TCP=y +CONFIG_NET_UDP=n +CONFIG_NET_ARP=y +CONFIG_NET_L2_BLUETOOTH=y +CONFIG_NET_L2_BLUETOOTH_SEC_LEVEL=1 +CONFIG_NET_LOG=y +CONFIG_NET_IPV6_RA_RDNSS=y +CONFIG_NET_IPV4=n +CONFIG_NET_IPV6=y +CONFIG_NET_IPV6_MAX_NEIGHBORS=8 +CONFIG_NET_MAX_CONTEXTS=5 +CONFIG_NET_SHELL=y + +CONFIG_NET_NBUF_RX_COUNT=16 +CONFIG_NET_NBUF_TX_COUNT=16 +CONFIG_NET_NBUF_DATA_SIZE=256 +CONFIG_NET_NBUF_DATA_COUNT=30 + +CONFIG_NET_SAMPLES_IP_ADDRESSES=y +CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2" + +CONFIG_NET_SAMPLES_MY_IPV4_ADDR="192.168.1.101" +CONFIG_NET_SAMPLES_PEER_IPV4_ADDR="192.168.1.10" + +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=3 + +CONFIG_PRINTK=y + +CONFIG_MQTT_LIB=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_TIMER_RANDOM_GENERATOR=y + +CONFIG_BLUETOOTH_RX_STACK_SIZE=1024 +CONFIG_BLUETOOTH_DEVICE_NAME="Zephyr" + +CONFIG_BLUETOOTH_L2CAP_TX_BUF_COUNT=3 +CONFIG_BLUETOOTH_L2CAP_TX_MTU=65 +CONFIG_BLUETOOTH_L2CAP_TX_USER_DATA_SIZE=4 + +CONFIG_BLUETOOTH_HCI_TX_STACK_SIZE=640 +CONFIG_BLUETOOTH_HCI_HOST=y +CONFIG_BLUETOOTH_RECV_IS_RX_THREAD=y +CONFIG_BLUETOOTH_HCI_CMD_COUNT=2 +CONFIG_BLUETOOTH_MAX_CMD_LEN=64 +CONFIG_BLUETOOTH_RX_BUF_COUNT=20 +CONFIG_BLUETOOTH_RX_BUF_LEN=1024 +CONFIG_BLUETOOTH_CONN=y +CONFIG_BLUETOOTH_SIGNING=y +CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BLUETOOTH_DEBUG=y +CONFIG_BLUETOOTH_DEBUG_LOG=y +CONFIG_BLUETOOTH_DEBUG_COLOR=y + +CONFIG_CONSOLE_SHELL=y +CONFIG_CONSOLE_SHELL_STACKSIZE=2000 +CONFIG_CONSOLE_SHELL_MAX_CMD_QUEUED=3 diff --git a/samples/net/mqtt_publisher/src/Makefile b/samples/net/mqtt_publisher/src/Makefile index 9715a81e71f..bd5dd34b81f 100644 --- a/samples/net/mqtt_publisher/src/Makefile +++ b/samples/net/mqtt_publisher/src/Makefile @@ -6,3 +6,7 @@ obj-y += main.o +ifeq ($(CONFIG_NET_L2_BLUETOOTH), y) +ccflags-y +=-I${ZEPHYR_BASE}/samples/bluetooth/ +obj-y += ../../../bluetooth/gatt/ipss.o +endif diff --git a/samples/net/mqtt_publisher/src/main.c b/samples/net/mqtt_publisher/src/main.c index 909a1d21123..ce7289bb28c 100644 --- a/samples/net/mqtt_publisher/src/main.c +++ b/samples/net/mqtt_publisher/src/main.c @@ -14,6 +14,12 @@ #include #include +#if defined(CONFIG_NET_L2_BLUETOOTH) +#include +#include +#include +#endif + #include "config.h" /** @@ -334,6 +340,29 @@ int set_addr(struct sockaddr *sock_addr, const char *addr, uint16_t port) return rc; } +#if defined(CONFIG_NET_L2_BLUETOOTH) +static bool bt_connected; + +static +void bt_connect_cb(struct bt_conn *conn, uint8_t err) +{ + bt_connected = true; +} + +static +void bt_disconnect_cb(struct bt_conn *conn, uint8_t reason) +{ + bt_connected = false; + printk("bt disconnected (reason %u)\n", reason); +} + +static +struct bt_conn_cb bt_conn_cb = { + .connected = bt_connect_cb, + .disconnected = bt_disconnect_cb, +}; +#endif + int network_setup(struct net_context **net_ctx, const char *local_addr, const char *server_addr, uint16_t server_port) { @@ -345,11 +374,37 @@ int network_setup(struct net_context **net_ctx, const char *local_addr, socklen_t addr_len = sizeof(struct sockaddr_in); sa_family_t family = AF_INET; #endif - struct sockaddr local_sock; - struct sockaddr server_sock; + struct sockaddr server_sock, local_sock; void *p; int rc; +#if defined(CONFIG_NET_L2_BLUETOOTH) + const char *progress_mark = "/-\\|"; + int i = 0; + + rc = bt_enable(NULL); + if (rc) { + printk("bluetooth init failed\n"); + return rc; + } + + ipss_init(); + bt_conn_cb_register(&bt_conn_cb); + rc = ipss_advertise(); + if (rc) { + printk("advertising failed to start\n"); + return rc; + } + + printk("\nwaiting for bt connection: "); + while (bt_connected == false) { + k_sleep(250); + printk("%c\b", progress_mark[i]); + i = (i + 1) % (sizeof(progress_mark) - 1); + } + printk("\n"); +#endif + rc = set_addr(&local_sock, local_addr, 0); if (rc) { printk("set_addr (local) error\n"); diff --git a/samples/net/mqtt_publisher/testcase.ini b/samples/net/mqtt_publisher/testcase.ini index 16ecfdae3c8..4daf6534fcb 100644 --- a/samples/net/mqtt_publisher/testcase.ini +++ b/samples/net/mqtt_publisher/testcase.ini @@ -2,3 +2,8 @@ tags = net mqtt build_only = true platform_whitelist = frdm_k64f + +[test_bt] +tags = net mqtt bluetooth +build_only = true +platform_whitelist = 96b_nitrogen diff --git a/samples/net/zoap_server/README.rst b/samples/net/zoap_server/README.rst index 562b777de17..d4ab9ce6e91 100644 --- a/samples/net/zoap_server/README.rst +++ b/samples/net/zoap_server/README.rst @@ -12,15 +12,20 @@ some adjustments to the configuration may be needed. The sample will listen for requests in the CoAP UDP port (5683) in the site-local IPv6 multicast address reserved for CoAP nodes. -The exported resource, with path '/test', will just respond any GET to -that path with the the type, code and message identification retrieved -from the request. The response will have this format: +The sample exports the following resources: .. code-block:: none - Type: - Code: - MID: + /test + /seg1/seg2/seg3 + /query + /separate + /large + /location-query + /large-update + +These resources allow a good part of the ETSI testcases to be run +against zoap-server. Building And Running ******************** @@ -37,6 +42,14 @@ It can be built and executed on QEMU as follows: make run + +Use this command on the host to run the`libcoap`_ implementation of +the ETSI testcases: + +.. code-block:: console + + sudo ./examples/etsi_coaptest.sh -i tap0 2001:db8::1 + To build the version supporting the TI CC2520 radio, use the supplied configuration file enabling IEEE 802.15.4: @@ -44,4 +57,7 @@ configuration file enabling IEEE 802.15.4: make CONF_FILE=prj_cc2520.conf run + .. _`net-tools`: https://gerrit.zephyrproject.org/r/gitweb?p=net-tools.git;a=tree + +.. _`libcoap`: https://github.com/obgm/libcoap diff --git a/samples/net/zoap_server/prj_cc2520.conf b/samples/net/zoap_server/prj_cc2520.conf index 934a1a5980a..b73aa209224 100644 --- a/samples/net/zoap_server/prj_cc2520.conf +++ b/samples/net/zoap_server/prj_cc2520.conf @@ -6,7 +6,6 @@ CONFIG_NET_L2_IEEE802154_ORFD_CHANNEL=20 CONFIG_NET_L2_IEEE802154_FRAGMENT=y CONFIG_NET_LOG=y CONFIG_NET_UDP=y -CONFIG_NET_YAIP=y CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_IEEE802154_CC2520=y CONFIG_ZOAP=y diff --git a/samples/net/zperf/prj_frdm_k64f_prof.conf b/samples/net/zperf/prj_frdm_k64f_prof.conf index edf0dd1a7c5..f9229eed732 100644 --- a/samples/net/zperf/prj_frdm_k64f_prof.conf +++ b/samples/net/zperf/prj_frdm_k64f_prof.conf @@ -3,7 +3,6 @@ CONFIG_NET_LOG=y CONFIG_NET_IPV6=y CONFIG_NET_IPV4=y CONFIG_NET_DHCPV4=y -CONFIG_NET_YAIP=y CONFIG_NET_UDP=y CONFIG_NET_TCP=y CONFIG_NET_STATISTICS=y diff --git a/samples/net/zperf/prj_qemu_x86.conf b/samples/net/zperf/prj_qemu_x86.conf index b9044b21904..5924af03ef0 100644 --- a/samples/net/zperf/prj_qemu_x86.conf +++ b/samples/net/zperf/prj_qemu_x86.conf @@ -3,7 +3,6 @@ CONFIG_NET_LOG=y CONFIG_NET_IPV6=y CONFIG_NET_IPV4=y CONFIG_NET_DHCPV4=n -CONFIG_NET_YAIP=y CONFIG_NET_UDP=y CONFIG_NET_TCP=n CONFIG_NET_STATISTICS=y diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index 08277c49702..b38e8e1ac60 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -120,7 +120,6 @@ net_dhcpv4_state_name(enum net_dhcpv4_state state) static const char * const name[] = { "init", "discover", - "offer", "request", "renewal", "ack" @@ -316,6 +315,7 @@ static void setup_header(struct net_buf *buf) udp->src_port = htons(DHCPV4_CLIENT_PORT); udp->dst_port = htons(DHCPV4_SERVER_PORT); udp->len = htons(len); + udp->chksum = 0; udp->chksum = ~net_calc_chksum_udp(buf); } @@ -709,7 +709,7 @@ static inline void handle_dhcpv4_reply(struct net_if *iface, uint8_t msg_type) * Rest of the replies are discarded. */ if (iface->dhcpv4.state == NET_DHCPV4_DISCOVER) { - if (msg_type != NET_DHCPV4_OFFER) { + if (msg_type != DHCPV4_MSG_TYPE_OFFER) { NET_DBG("Reply ignored"); return; } @@ -724,7 +724,7 @@ static inline void handle_dhcpv4_reply(struct net_if *iface, uint8_t msg_type) iface->dhcpv4.state == NET_DHCPV4_RENEWAL) { uint32_t timeout; - if (msg_type != NET_DHCPV4_ACK) { + if (msg_type != DHCPV4_MSG_TYPE_ACK) { NET_DBG("Reply ignored"); return; } diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index f51faafa521..e95f430b759 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -80,8 +80,6 @@ static inline const char *dhcpv4state2str(enum net_dhcpv4_state state) return "init"; case NET_DHCPV4_DISCOVER: return "discover"; - case NET_DHCPV4_OFFER: - return "offer"; case NET_DHCPV4_REQUEST: return "request"; case NET_DHCPV4_RENEWAL: diff --git a/subsys/net/lib/mqtt/mqtt.c b/subsys/net/lib/mqtt/mqtt.c index 9b57c8cf410..a6500bc9edf 100644 --- a/subsys/net/lib/mqtt/mqtt.c +++ b/subsys/net/lib/mqtt/mqtt.c @@ -113,16 +113,16 @@ exit_disconnect: } /** - * @brief mqtt_tx_pub_msgs Writes the MQTT PUBxxx msg indicated by pkt_type - * with identifier 'id' - * @param [in] ctx MQTT context - * @param [in] id MQTT packet identifier - * @param [in] pkt_type MQTT packet type - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed to - * this routine - * @return -ENOMEM if a tx buffer is not available - * @return -EIO on network error + * Writes the MQTT PUBxxx msg indicated by pkt_type with identifier 'id' + * + * @param [in] ctx MQTT context + * @param [in] id MQTT packet identifier + * @param [in] pkt_type MQTT packet type + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM if a tx buffer is not available + * @retval -EIO on network error */ static int mqtt_tx_pub_msgs(struct mqtt_ctx *ctx, uint16_t id, @@ -421,16 +421,19 @@ exit_connect: } /** - * @brief mqtt_rx_pub_msgs Parses and validates the MQTT PUBxxxx message - * contained in the rx buffer. It validates against - * message structure and Packet Identifier. - * @details For the MQTT PUBREC and PUBREL messages, this - * function writes the corresponding MQTT PUB msg. - * @param ctx MQTT context - * @param rx RX buffer - * @param type MQTT Packet type - * @return 0 on success - * @return -EINVAL on error + * Parses and validates the MQTT PUBxxxx message contained in the rx buffer. + * + * + * @details It validates against message structure and Packet Identifier. + * For the MQTT PUBREC and PUBREL messages, this function writes the + * corresponding MQTT PUB msg. + * + * @param ctx MQTT context + * @param rx RX buffer + * @param type MQTT Packet type + * + * @retval 0 on success + * @retval -EINVAL on error */ static int mqtt_rx_pub_msgs(struct mqtt_ctx *ctx, struct net_buf *rx, @@ -626,14 +629,15 @@ int mqtt_rx_publish(struct mqtt_ctx *ctx, struct net_buf *rx) } /** - * @brief mqtt_linearize_buffer Linearize an IP fragmented buffer - * @param [in] ctx MQTT context structure - * @param [in] rx RX IP stack buffer - * @param [in] min_size Min message size allowed. This allows us - * to exit if the rx buffer is shorter - * than the expected msg size - * @return Data buffer - * @return NULL on error + * Linearizes an IP fragmented buffer + * + * @param [in] ctx MQTT context structure + * @param [in] rx RX IP stack buffer + * @param [in] min_size Min message size allowed. This allows us to exit if the + * rx buffer is shorter than the expected msg size + * + * @retval Data buffer + * @retval NULL on error */ static struct net_buf *mqtt_linearize_buffer(struct mqtt_ctx *ctx, struct net_buf *rx, @@ -673,18 +677,19 @@ exit_error: } /** - * @brief mqtt_publisher_parser Calls the appropriate rx routine for the MQTT - * message contained in rx - * @details On error, this routine will execute the - * 'ctx->malformed' callback (if defined) - * @param ctx MQTT context - * @param rx RX buffer - * @return 0 on success - * @return -EINVAL if an unknown message is received - * @return -ENOMEM if no data buffer is available - * @return mqtt_rx_connack, mqtt_rx_puback, mqtt_rx_pubrec, - * mqtt_rx_pubcomp, and mqtt_rx_pingresp - * return codes + * Calls the appropriate rx routine for the MQTT message contained in rx + * + * @details On error, this routine will execute the 'ctx->malformed' callback + * (if defined) + * + * @param ctx MQTT context + * @param rx RX buffer + * + * @retval 0 on success + * @retval -EINVAL if an unknown message is received + * @retval -ENOMEM if no data buffer is available + * @retval mqtt_rx_connack, mqtt_rx_puback, mqtt_rx_pubrec, mqtt_rx_pubcomp + * and mqtt_rx_pingresp return codes */ static int mqtt_publisher_parser(struct mqtt_ctx *ctx, struct net_buf *rx) @@ -738,18 +743,19 @@ exit_parser: /** - * @brief mqtt_subscriber_parser Calls the appropriate rx routine for the MQTT - * message contained in rx - * @details On error, this routine will execute the - * 'ctx->malformed' callback (if defined) - * @param ctx MQTT context - * @param rx RX buffer - * @return 0 on success - * @return -EINVAL if an unknown message is received - * @return -ENOMEM if no data buffer is available - * @return mqtt_rx_publish, mqtt_rx_pubrel, mqtt_rx_pubrel, - * mqtt_rx_suback - * return codes + * Calls the appropriate rx routine for the MQTT message contained in rx + * + * @details On error, this routine will execute the 'ctx->malformed' callback + * (if defined) + * + * @param ctx MQTT context + * @param rx RX buffer + * + * @retval 0 on success + * @retval -EINVAL if an unknown message is received + * @retval -ENOMEM if no data buffer is available + * @retval mqtt_rx_publish, mqtt_rx_pubrel, mqtt_rx_pubrel and mqtt_rx_suback + * return codes */ static int mqtt_subscriber_parser(struct mqtt_ctx *ctx, struct net_buf *rx) diff --git a/subsys/net/lib/mqtt/mqtt_pkt.c b/subsys/net/lib/mqtt/mqtt_pkt.c index cd3c2b13adc..a04ee8f70ab 100644 --- a/subsys/net/lib/mqtt/mqtt_pkt.c +++ b/subsys/net/lib/mqtt/mqtt_pkt.c @@ -50,21 +50,22 @@ QoS_SIZE) /** - * @brief mqtt_strlen Enhanced strlen function - * @details This function is introduced to allow developers to - * pass null strings to functions that compute the length - * of strings. - * strlen returns random values for null arguments, so - * mqtt_strlen(NULL) is quite useful when optional strings - * are allowed by mqtt-related functions. For example: - * username in the MQTT CONNECT message is an optional - * parameter, so connect(..., username = NULL, ...) will - * work fine without passing an additional parameter like: - * connect(.., is_username_present, username, ...) or - * connect(.., username, username_len, ...). - * @param str C-string or NULL - * @return 0 for NULL - * @return strlen otherwise + * Enhanced strlen function + * + * @details This function is introduced to allow developers to pass null strings + * to functions that compute the length of strings. strlen returns random values + * for null arguments, so mqtt_strlen(NULL) is quite useful when optional + * strings are allowed by mqtt-related functions. For example: username in the + * MQTT CONNECT message is an optional parameter, so + * connect(..., username = NULL, ...) will work fine without passing an + * additional parameter like: + * connect(.., is_username_present, username, ...) or + * connect(.., username, username_len, ...). + * + * @param str C-string or NULL + * + * @retval 0 for NULL + * @retval strlen otherwise */ static inline uint16_t mqtt_strlen(const char *str) @@ -77,14 +78,13 @@ uint16_t mqtt_strlen(const char *str) } /** - * @brief compute_rlen_size Computes the amount of bytes needed to - * codify the value stored in len - * @details See MQTT 2.2.3, Table 2.4 - * @param [out] size Amount of bytes required to codify the value - * stored in len - * @param [in] len Value to be codified - * @return 0 on success - * @return -EINVAL is len is out of range + * Computes the amount of bytes needed to codify the value stored in len. + * + * @param [out] size Amount of bytes required to codify the value stored in len + * @param [in] len Value to be codified + * + * @retval 0 on success + * @retval -EINVAL */ static int compute_rlen_size(uint16_t *size, uint32_t len) @@ -105,11 +105,12 @@ int compute_rlen_size(uint16_t *size, uint32_t len) } /** - * @brief rlen_encode Remaining Length encoding algorithm - * @details See MQTT 2.2.3 Remaining Length - * @param [out] buf Buffer where the encoded value will be stored - * @param [in] len Value to encode - * @return 0 always + * Remaining Length encoding algorithm. See MQTT 2.2.3 Remaining Length + * + * @param [out] buf Buffer where the encoded value will be stored + * @param [in] len Value to encode + * + * @retval 0 always */ static int rlen_encode(uint8_t *buf, int len) { @@ -133,15 +134,15 @@ static int rlen_encode(uint8_t *buf, int len) } /** - * @brief rlen_decode Remaining Length decoding algorithm - * @details See MQTT 2.2.3 Remaining Length - * @param [out] rlen Remaining Length (decoded) - * @param [out] rlen_size Number of bytes required to codify rlen's value - * @param [in] buf Buffer where the codified Remaining Length - * is codified - * @param [in] size Buffer size - * @return 0 on success - * @return -ENOMEM if size < 4 + * Remaining Length decoding algorithm. See MQTT 2.2.3 Remaining Length + * + * @param [out] rlen Remaining Length (decoded) + * @param [out] rlen_size Number of bytes required to codify rlen's value + * @param [in] buf Buffer where the codified Remaining Length is codified + * @param [in] size Buffer size + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ static int rlen_decode(uint16_t *rlen, uint16_t *rlen_size, uint8_t *buf, uint16_t size) @@ -184,23 +185,22 @@ int mqtt_pack_connack(uint8_t *buf, uint16_t *length, uint16_t size, } /** - * @brief pack_pkt_id Packs a message that only contains the - * Packet Identifier as payload. - * @details Many MQTT messages only codify the packet type, - * reserved flags and the Packet Identifier as payload, - * so this function is used by those MQTT messages. + * Packs a message that only contains the Packet Identifier as payload. * - * The total size of this message is always 4 bytes, - * with a payload of only 2 bytes to codify the - * identifier. - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] type MQTT Control Packet type + * @details Many MQTT messages only codify the packet type, reserved flags and + * the Packet Identifier as payload, so this function is used by those MQTT + * messages. The total size of this message is always 4 bytes, with a payload + * of only 2 bytes to codify the identifier. + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer's size + * @param [in] type MQTT Control Packet type * @param [in] reserved Control Packet Reserved Flags. See MQTT 2.2.2 Flags - * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet Identifier - * @return 0 on success - * @return -ENOMEM if size < 4 + * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet Identifier + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ static int pack_pkt_id(uint8_t *buf, uint16_t *length, uint16_t size, @@ -415,15 +415,15 @@ int mqtt_pack_connect(uint8_t *buf, uint16_t *length, uint16_t size, } /** - * @brief recover_value_len Recovers the length and sets val to point to - * the beginning of the value - * @param [in] buf Buffer where the length and value are stored - * @param [in] length Buffer's length - * @param [out] val Pointer to the beginning of the value - * @param [out] val_len Recovered value's length - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Recovers the length and sets val to point to the beginning of the value + * + * @param [in] buf Buffer where the length and value are stored + * @param [in] length Buffer's length + * @param [out] val Pointer to the beginning of the value + * @param [out] val_len Recovered value's length + * + * @retval 0 on success + * @retval -EINVAL */ static int recover_value_len(uint8_t *buf, uint16_t length, uint8_t **val, @@ -568,17 +568,18 @@ int mqtt_unpack_connect(uint8_t *buf, uint16_t length, } /** - * @brief subscribe_size Computes the packet size for the SUBSCRIBE - * and UNSUBSCRIBE messages without considering - * the packet type field size (1 byte) - * @param rlen_size Remaining length size - * @param payload_size SUBSCRIBE or UNSUBSCRIBE payload size - * @param items Number of topics - * @param topics Array of C-strings containing the topics - * to subscribe to - * @param with_qos 0 for UNSUBSCRIBE, != 0 for SUBSCRIBE - * @return 0 on success - * @return -EINVAL on error + * Computes the packet size for the SUBSCRIBE and UNSUBSCRIBE messages + * + * This routine does not consider the packet type field size (1 byte) + * + * @param rlen_size Remaining length size + * @param payload_size SUBSCRIBE or UNSUBSCRIBE payload size + * @param items Number of topics + * @param topics Array of C-strings containing the topics to subscribe to + * @param with_qos 0 for UNSUBSCRIBE, != 0 for SUBSCRIBE + * + * @retval 0 on success + * @retval -EINVAL on error */ static int subscribe_size(uint16_t *rlen_size, uint16_t *payload_size, uint8_t items, @@ -607,19 +608,18 @@ int subscribe_size(uint16_t *rlen_size, uint16_t *payload_size, uint8_t items, } /** - * @brief mqtt_pack_subscribe_unsubscribe - * @details Packs the SUBSCRIBE and UNSUBSCRIBE messages - * @param buf Buffer where the message will be stored - * @param pkt_id Packet Identifier - * @param items Number of topics - * @param topics Array of C-strings containing the topics - * to subscribe to - * @param qos Array of QoS' values, qos[i] is the QoS of topic[i] - * @param type MQTT_SUBSCRIBE or MQTT_UNSUBSCRIBE - * @return 0 on success - * @return -EINVAL if invalid parameters were passed as arguments - * @return -ENOMEM if buf has no enough space to store the - * resultant message + * Packs the SUBSCRIBE and UNSUBSCRIBE messages + * + * @param buf Buffer where the message will be stored + * @param pkt_id Packet Identifier + * @param items Number of topics + * @param topics Array of C-strings containing the topics to subscribe to + * @param qos Array of QoS' values, qos[i] is the QoS of topic[i] + * @param type MQTT_SUBSCRIBE or MQTT_UNSUBSCRIBE + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM */ static int mqtt_pack_subscribe_unsubscribe(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id, @@ -969,19 +969,20 @@ int mqtt_unpack_connack(uint8_t *buf, uint16_t length, uint8_t *session, } /** - * @brief pack_zerolen Packs a zero length message - * @details This function packs MQTT messages with no - * payload. No validations are made about the - * input arguments, besides 'size' that must be - * at least 2 bytes - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_type MQTT Control Packet Type. See MQTT 2.2.1 - * @param [in] reserved Reserved bits. See MQTT 2.2 - * @return 0 on success - * @return -ENOMEM if buf has no enough reserved space - * to store the resultant message + * Packs a zero length message + * + * @details This function packs MQTT messages with no payload. No validations + * are made about the input arguments, besides 'size' that must be at least + * 2 bytes + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_type MQTT Control Packet Type. See MQTT 2.2.1 + * @param [in] reserved Reserved bits. See MQTT 2.2 + * + * @retval 0 on success + * @retval -ENOMEM */ static int pack_zerolen(uint8_t *buf, uint16_t *length, uint16_t size, @@ -1014,16 +1015,16 @@ int mqtt_pack_disconnect(uint8_t *buf, uint16_t *length, uint16_t size) } /** - * @brief unpack_pktid Unpacks a MQTT message with a Packet Id - * as payload - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] type MQTT Control Packet type - * @param [out] reserved Reserved flags - * @param [out] pkt_id Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks a MQTT message with a Packet Id as payload + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] type MQTT Control Packet type + * @param [out] reserved Reserved flags + * @param [out] pkt_id Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL */ static int unpack_pktid(uint8_t *buf, uint16_t length, enum mqtt_packet *type, @@ -1045,26 +1046,22 @@ int unpack_pktid(uint8_t *buf, uint16_t length, enum mqtt_packet *type, } /** - * @brief unpack_pktid_validate Unpacks and validates a MQTT message - * containing a Packet Identifier - * @details The message codified in buf must contain a - * 1) packet type, 2) reserved flags and - * 3) packet identifier. - * The user must provide the expected packet type - * and expected reserved flags. - * See MQTT 2.2.2 Flags. - * If the message contains different values for - * type and reserved flags than the ones passed as - * arguments, the function will return -EINVAL - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id Packet Identifier - * @param [in] expected_type Expected MQTT Control Packet type - * @param [in] expected_reserv Expected Reserved Flags - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine or if - * any test failed + * Unpacks and validates a MQTT message containing a Packet Identifier + * + * @details The message codified in buf must contain a 1) packet type, + * 2) reserved flags and 3) packet identifier. The user must provide the + * expected packet type and expected reserved flags. See MQTT 2.2.2 Flags. + * If the message contains different values for type and reserved flags + * than the ones passed as arguments, the function will return -EINVAL + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id Packet Identifier + * @param [in] expected_type Expected MQTT Control Packet type + * @param [in] expected_reserv Expected Reserved Flags + * + * @retval 0 on success + * @retval -EINVAL */ static int unpack_pktid_validate(uint8_t *buf, uint16_t length, uint16_t *pkt_id, @@ -1117,14 +1114,15 @@ int mqtt_unpack_unsuback(uint8_t *buf, uint16_t length, uint16_t *pkt_id) } /** - * @brief unpack_zerolen Unpacks a zero-length MQTT message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_type MQTT Control Packet type - * @param [out] reserved Reserved flags - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks a zero-length MQTT message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_type MQTT Control Packet type + * @param [out] reserved Reserved flags + * + * @retval 0 on success + * @retval -EINVAL */ static int unpack_zerolen(uint8_t *buf, uint16_t length, enum mqtt_packet *pkt_type, @@ -1145,14 +1143,15 @@ int unpack_zerolen(uint8_t *buf, uint16_t length, enum mqtt_packet *pkt_type, } /** - * @brief unpack_zerolen_validate Unpacks and validates a zero-len MQTT message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param expected_type Expected MQTT Control Packet type - * @param expected_reserved Expected Reserved Flags - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks and validates a zero-len MQTT message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param expected_type Expected MQTT Control Packet type + * @param expected_reserved Expected Reserved Flags + * + * @retval 0 on success + * @retval -EINVAL */ static int unpack_zerolen_validate(uint8_t *buf, uint16_t length, diff --git a/subsys/net/lib/mqtt/mqtt_pkt.h b/subsys/net/lib/mqtt/mqtt_pkt.h index db9721a3274..87db2bab137 100644 --- a/subsys/net/lib/mqtt/mqtt_pkt.h +++ b/subsys/net/lib/mqtt/mqtt_pkt.h @@ -10,8 +10,8 @@ * @brief MQTT v3.1.1 packet library, see: * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html * - * This file is part of the Zephyr Project - * http://www.zephyrproject.org + * This file is part of the Zephyr Project + * http://www.zephyrproject.org */ #ifndef _MQTT_PKT_H_ @@ -25,368 +25,383 @@ #define MQTT_PACKET_TYPE(first_byte) (((first_byte) & 0xF0) >> 4) /** - * @brief mqtt_pack_connack Packs the MQTT CONNACK message - * @details See MQTT 3.2 CONNACK - Acknowledge connection - * request - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] session_present Session Present parameter (0 for clean session) - * @param [in] ret_code Connect return code. See MQTT 3.2.2.3 - * @return 0 on success - * @return -ENOMEM if size < 4 + * Packs the MQTT CONNACK message. See MQTT 3.2 CONNACK - Acknowledge + * connection request + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] session_present Session Present parameter (0 for clean session) + * @param [in] ret_code Connect return code. See MQTT 3.2.2.3 + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ int mqtt_pack_connack(uint8_t *buf, uint16_t *length, uint16_t size, uint8_t session_present, uint8_t ret_code); /** - * @brief mqtt_pack_puback Packs the MQTT PUBACK message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet - * Identifier - * @return 0 on success - * @return -ENOMEM if size < 4 + * Packs the MQTT PUBACK message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet Identifier + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ int mqtt_pack_puback(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id); /** - * @brief mqtt_pack_pubrec Packs the MQTT PUBREC message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet - * Identifier - * @return 0 on success - * @return -ENOMEM if size < 4 + * Packs the MQTT PUBREC message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet Identifier + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ int mqtt_pack_pubrec(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id); /** - * @brief mqtt_pack_puback Packs the MQTT PUBREL message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet - * Identifier - * @return 0 on success - * @return -ENOMEM if size < 4 + * Packs the MQTT PUBREL message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet Identifier + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ int mqtt_pack_pubrel(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id); /** - * @brief mqtt_pack_pubcomp Packs the MQTT PUBCOMP message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet - * Identifier - * @return 0 on success - * @return -ENOMEM if size < 4 + * Packs the MQTT PUBCOMP message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet Identifier + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ int mqtt_pack_pubcomp(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id); /** - * @brief mqtt_pack_suback Packs the MQTT SUBACK message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 - * @param [in] elements Number of elements in the granted_qos array - * @param [in] granted_qos Array where the QoS values are stored - * See MQTT 3.9 SUBACK, 3.9.3 Payload - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT SUBACK message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 + * @param [in] elements Number of elements in the granted_qos array + * @param [in] granted_qos Array where the QoS values are stored + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM */ int mqtt_pack_suback(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id, uint8_t elements, enum mqtt_qos granted_qos[]); /** - * @brief mqtt_pack_connect Packs the MQTT CONNECT message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] msg MQTT CONNECT msg - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT CONNECT message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] msg MQTT CONNECT msg + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM */ int mqtt_pack_connect(uint8_t *buf, uint16_t *length, uint16_t size, struct mqtt_connect_msg *msg); /** - * @brief mqtt_unpack_connect Unpacks the MQTT CONNECT message - * @param [in] buf Buffer where the message is stored - * @param [in] length MQTT CONNECT message's length - * @param [out] msg MQTT CONNECT parameters - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT CONNECT message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length MQTT CONNECT message's length + * @param [out] msg MQTT CONNECT parameters + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_connect(uint8_t *buf, uint16_t length, struct mqtt_connect_msg *msg); /** - * @brief mqtt_pack_subscribe Packs the MQTT SUBSCRIBE message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 - * @param [in] items Number of elements in topics - * @param [in] topics Array of topics. - * For example: {"sensors", "lights", "doors"} - * @param [in] qos Array of QoS values per topic. For example: - {MQTT_QoS1, MQTT_QoS2, MQTT_QoS0} - NOTE: qos and topics must have the same - cardinality (# of items) - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT SUBSCRIBE message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 + * @param [in] items Number of elements in topics + * @param [in] topics Array of topics. + * For example: {"sensors", "lights", "doors"} + * @param [in] qos Array of QoS values per topic. + * For example: {MQTT_QoS1, MQTT_QoS2, MQTT_QoS0} + * NOTE: qos and topics must have the same cardinality + * (# of items) + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM */ int mqtt_pack_subscribe(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id, uint8_t items, const char *topics[], const enum mqtt_qos qos[]); /** - * @brief mqtt_pack_unsubscribe Packs the MQTT UNSUBSCRIBE message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 - * @param [in] items Number of elements in topics - * @param [in] topics Array of topics. - * For example: {"sensors", "lights", "doors"} - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT UNSUBSCRIBE message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 + * @param [in] items Number of elements in topics + * @param [in] topics Array of topics. + * For example: {"sensors", "lights", "doors"} + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM */ int mqtt_pack_unsubscribe(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id, uint8_t items, const char *topics[]); /** - * @brief mqtt_unpack_subscribe Unpacks the MQTT SUBSCRIBE message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 - * @param [out] items Number of recovered topics - * @param [in] elements Max number of topics to recover from buf - * @param [out] topics Array of topics. Each element in this array - * points to the beginning of a topic in buf - * @param [out] topic_len Array of topics' length. Each element in this - * array contains the length of the - * @param [out] qos Array of QoS, - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT SUBSCRIBE message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 + * @param [out] items Number of recovered topics + * @param [in] elements Max number of topics to recover from buf + * @param [out] topics Array of topics. Each element in this array points to + * the beginning of a topic in buf + * @param [out] topic_len Array containing the length of each topic in topics + * @param [out] qos Array of QoS values + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_subscribe(uint8_t *buf, uint16_t length, uint16_t *pkt_id, uint8_t *items, uint8_t elements, char *topics[], uint16_t topic_len[], enum mqtt_qos qos[]); /** - * @brief mqtt_unpack_suback Unpacks the MQTT SUBACK message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 - * @param [out] items Number of recovered topics - * @param [in] elements Max number of topics to recover from buf - * @param [out] granted_qos Granted QoS values per topic. See MQTT 3.9 - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT SUBACK message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id MQTT Message Packet Identifier. See MQTT 2.3.1 + * @param [out] items Number of recovered topics + * @param [in] elements Max number of topics to recover from buf + * @param [out] granted_qos Granted QoS values per topic. See MQTT 3.9 + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_suback(uint8_t *buf, uint16_t length, uint16_t *pkt_id, uint8_t *items, uint8_t elements, enum mqtt_qos granted_qos[]); /** - * @brief mqtt_pack_publish Packs the MQTT PUBLISH message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] msg MQTT PUBLISH message - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT PUBLISH message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] msg MQTT PUBLISH message + * + * @retval 0 on success + * @retval -EINVAL + * @retval -ENOMEM */ int mqtt_pack_publish(uint8_t *buf, uint16_t *length, uint16_t size, struct mqtt_publish_msg *msg); /** - * @brief mqtt_unpack_publish Unpacks the MQTT PUBLISH message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] msg MQTT PUBLISH message - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT PUBLISH message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] msg MQTT PUBLISH message + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_publish(uint8_t *buf, uint16_t length, struct mqtt_publish_msg *msg); /** - * @brief mqtt_unpack_connack Unpacks the MQTT CONNACK message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] session Session Present. See MQTT 3.2.2.2 - * @param [out] connect_rc CONNECT return code. See MQTT 3.2.2.3 - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT CONNACK message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] session Session Present. See MQTT 3.2.2.2 + * @param [out] connect_rc CONNECT return code. See MQTT 3.2.2.3 + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_connack(uint8_t *buf, uint16_t length, uint8_t *session, uint8_t *connect_rc); /** - * @brief mqtt_pack_pingreq Packs the MQTT PINGREQ message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @return 0 on success - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT PINGREQ message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * + * @retval 0 on success + * @retval -ENOMEM */ int mqtt_pack_pingreq(uint8_t *buf, uint16_t *length, uint16_t size); /** - * @brief mqtt_pack_pingresp Packs the MQTT PINGRESP message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @return 0 on success - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT PINGRESP message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * + * @retval 0 on success + * @retval -ENOMEM */ int mqtt_pack_pingresp(uint8_t *buf, uint16_t *length, uint16_t size); /** - * @brief mqtt_pack_disconnect Packs the MQTT DISCONNECT message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @return 0 on success - * @return -ENOMEM if buf does not have enough reserved - * space to store the resultant message + * Packs the MQTT DISCONNECT message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * + * @retval 0 on success + * @retval -ENOMEM */ int mqtt_pack_disconnect(uint8_t *buf, uint16_t *length, uint16_t size); /** - * @brief mqtt_pack_unsuback Packs the MQTT UNSUBACK message - * @param [out] buf Buffer where the resultant message is stored - * @param [out] length Number of bytes required to codify the message - * @param [in] size Buffer's size - * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet - * Identifier - * @return 0 on success - * @return -ENOMEM if size < 4 + * Packs the MQTT UNSUBACK message + * + * @param [out] buf Buffer where the resultant message is stored + * @param [out] length Number of bytes required to codify the message + * @param [in] size Buffer size + * @param [in] pkt_id Packet Identifier. See MQTT 2.3.1 Packet Identifier + * + * @retval 0 on success + * @retval -ENOMEM if size < 4 */ int mqtt_pack_unsuback(uint8_t *buf, uint16_t *length, uint16_t size, uint16_t pkt_id); /** - * @brief mqtt_unpack_puback Unpacks the MQTT PUBACK message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine or if - * buf does not contain the desired msg + * Unpacks the MQTT PUBACK message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_puback(uint8_t *buf, uint16_t length, uint16_t *pkt_id); /** - * @brief mqtt_unpack_pubrec Unpacks the MQTT PUBREC message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine or if - * buf does not contain the desired msg + * Unpacks the MQTT PUBREC message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_pubrec(uint8_t *buf, uint16_t length, uint16_t *pkt_id); /** - * @brief mqtt_unpack_pubrel Unpacks the MQTT PUBREL message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine or if - * buf does not contain the desired msg + * Unpacks the MQTT PUBREL message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_pubrel(uint8_t *buf, uint16_t length, uint16_t *pkt_id); /** - * @brief mqtt_unpack_pubcomp Unpacks the MQTT PUBCOMP message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine or if - * buf does not contain the desired msg + * Unpacks the MQTT PUBCOMP message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_pubcomp(uint8_t *buf, uint16_t length, uint16_t *pkt_id); /** - * @brief mqtt_unpack_unsuback Unpacks the MQTT UNSUBACK message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @param [out] pkt_id Packet Identifier - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine or if - * buf does not contain the desired msg + * Unpacks the MQTT UNSUBACK message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * @param [out] pkt_id Packet Identifier + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_unsuback(uint8_t *buf, uint16_t length, uint16_t *pkt_id); /** - * @brief mqtt_unpack_pingreq Unpacks the MQTT PINGREQ message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT PINGREQ message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_pingreq(uint8_t *buf, uint16_t length); /** - * @brief mqtt_unpack_pingresp Unpacks the MQTT PINGRESP message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT PINGRESP message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_pingresp(uint8_t *buf, uint16_t length); /** - * @brief mqtt_unpack_disconnect Unpacks the MQTT DISCONNECT message - * @param [in] buf Buffer where the message is stored - * @param [in] length Message's length - * @return 0 on success - * @return -EINVAL if an invalid parameter was passed - * as an argument to this routine + * Unpacks the MQTT DISCONNECT message + * + * @param [in] buf Buffer where the message is stored + * @param [in] length Message's length + * + * @retval 0 on success + * @retval -EINVAL */ int mqtt_unpack_disconnect(uint8_t *buf, uint16_t length); diff --git a/subsys/net/lib/zoap/zoap.c b/subsys/net/lib/zoap/zoap.c index 6ff02b2f85f..9ffd4ece308 100644 --- a/subsys/net/lib/zoap/zoap.c +++ b/subsys/net/lib/zoap/zoap.c @@ -548,7 +548,7 @@ static zoap_method_t method_from_code(const struct zoap_resource *resource, } } -static bool is_request(struct zoap_packet *pkt) +static bool is_request(const struct zoap_packet *pkt) { uint8_t code = zoap_header_get_code(pkt); @@ -1210,15 +1210,16 @@ struct block_transfer { bool more; }; -static unsigned int get_block_option(struct zoap_packet *pkt, uint16_t code) +static int get_block_option(const struct zoap_packet *pkt, uint16_t code) { struct zoap_option option; unsigned int val; int count = 1; count = zoap_find_options(pkt, code, &option, count); - if (count <= 0) - return 0; + if (count <= 0) { + return -ENOENT; + } val = zoap_option_value_to_int(&option); @@ -1230,15 +1231,15 @@ static int update_descriptive_block(struct zoap_block_context *ctx, { size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4); - if (block == 0) { - return -ENOENT; + if (block == -ENOENT) { + return 0; } if (size && ctx->total_size && ctx->total_size != size) { return -EINVAL; } - if (ctx->block_size > 0 && GET_BLOCK_SIZE(block) > ctx->block_size) { + if (ctx->current > 0 && GET_BLOCK_SIZE(block) > ctx->block_size) { return -EINVAL; } @@ -1250,7 +1251,7 @@ static int update_descriptive_block(struct zoap_block_context *ctx, ctx->total_size = size; } ctx->current = new_current; - ctx->block_size = GET_BLOCK_SIZE(block); + ctx->block_size = min(GET_BLOCK_SIZE(block), ctx->block_size); return 0; } @@ -1260,7 +1261,7 @@ static int update_control_block1(struct zoap_block_context *ctx, { size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4); - if (block == 0) { + if (block == -ENOENT) { return 0; } @@ -1283,7 +1284,7 @@ static int update_control_block2(struct zoap_block_context *ctx, { size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4); - if (block == 0) { + if (block == -ENOENT) { return 0; } @@ -1296,23 +1297,24 @@ static int update_control_block2(struct zoap_block_context *ctx, } ctx->current = new_current; - ctx->block_size = GET_BLOCK_SIZE(block); - ctx->total_size = size; + ctx->block_size = min(GET_BLOCK_SIZE(block), ctx->block_size); return 0; } -int zoap_update_from_block(struct zoap_packet *pkt, +int zoap_update_from_block(const struct zoap_packet *pkt, struct zoap_block_context *ctx) { - unsigned int block1, block2, size1, size2; - int r; + int r, block1, block2, size1, size2; block1 = get_block_option(pkt, ZOAP_OPTION_BLOCK1); block2 = get_block_option(pkt, ZOAP_OPTION_BLOCK2); size1 = get_block_option(pkt, ZOAP_OPTION_SIZE1); size2 = get_block_option(pkt, ZOAP_OPTION_SIZE2); + size1 = size1 == -ENOENT ? 0 : size1; + size2 = size2 == -ENOENT ? 0 : size2; + if (is_request(pkt)) { r = update_control_block2(ctx, block2, size2); if (r) {