7#ifdef USE_OTA_ENCRYPTION
22#if defined(USE_ESP8266) || defined(USE_RP2) || defined(USE_LIBRETINY) || \
23 (defined(USE_ESP32) && defined(CONFIG_LWIP_TCPIP_CORE_LOCKING))
24#define ESPHOME_OTA_UDP
25#define ESPHOME_OTA_UDP_LWIP
26#include "lwip/ip_addr.h"
29#if defined(USE_LIBRETINY) && !LWIP_TCPIP_CORE_LOCKING
31#undef ESPHOME_OTA_UDP_LWIP
33#elif defined(USE_HOST)
34#define ESPHOME_OTA_UDP
48#ifdef USE_OTA_PASSWORD
52#ifdef USE_OTA_ENCRYPTION
57#ifdef USE_OTA_PASSWORD
63 static_assert(B,
"set_auth_password() requires the OTA auth path to be compiled. "
64 "Add 'password: \"\"' (empty string) to your 'ota: - platform: esphome' "
65 "config to enable runtime password rotation.");
69#ifdef USE_OTA_ENCRYPTION
77 void setup()
override;
93#ifdef ESPHOME_OTA_UDP_LWIP
102#ifdef ESPHOME_OTA_UDP_LWIP
103 struct udp_pcb *
pcb{
nullptr};
106 std::unique_ptr<socket::Socket>
sock;
135#ifdef ESPHOME_OTA_UDP_LWIP
136 static void udp_recv_cb(
void *arg,
struct udp_pcb *pcb,
struct pbuf *p,
const ip_addr_t *addr, uint16_t port);
144#ifdef ESPHOME_OTA_UDP
145 if (this->
udp_ !=
nullptr)
150#ifdef USE_OTA_PASSWORD
161#ifdef USE_OTA_ENCRYPTION
171 uint8_t
frame_buf[noise::FRAME_HEADER_SIZE + 1 + noise::MAX_HANDSHAKE_SIZE];
197#ifdef USE_OTA_ENCRYPTION
198 if (this->
noise_ !=
nullptr)
206#ifdef USE_OTA_ENCRYPTION
207 if (this->
noise_ !=
nullptr)
217#if USE_OTA_VERSION == 2
227#ifdef USE_SOCKET_IMPL_LWIP_TCP
241 inline bool read_size_(uint8_t *buf,
size_t &
size,
const LogString *desc);
245 bool try_read_(
size_t to_read,
const LogString *desc);
246 bool try_write_(
size_t to_write,
const LogString *desc);
248 inline bool would_block_(
int error_code)
const {
return error_code == EAGAIN || error_code == EWOULDBLOCK; }
264 uint8_t error_byte =
static_cast<uint8_t
>(error);
265 this->
client_->write(&error_byte, 1);
270#ifdef USE_OTA_PASSWORD
274#ifdef USE_OTA_ENCRYPTION
276#ifdef USE_OTA_ENCRYPTION_PROVISIONED
287#ifdef ESPHOME_OTA_UDP_LWIP
292 static_assert(
sizeof(UdpLink *) ==
sizeof(
uint32_t),
"clearing client_connect_time_ must clear udp_");
295#ifdef ESPHOME_OTA_UDP
296 UdpLink *
udp_{
nullptr};
299#if defined(ESPHOME_OTA_UDP) && defined(USE_OTA_ENCRYPTION)
307#ifdef USE_OTA_ENCRYPTION
312 "OTA_BUFFER_SIZE must fit a full encrypted data frame");
314#ifdef USE_OTA_DEFLATE
333 static_assert(!ota::OTABackend::supports_compression(),
334 "USE_OTA_DEFLATE is for backends that cannot store a gzip image");
342 static constexpr uint8_t
MAGIC_BYTES[5] = {0x6C, 0x26, 0xF7, 0x5C, 0x45};
345#ifdef USE_OTA_PARTITIONS
355#ifdef USE_OTA_PASSWORD
ESPHomeOTAComponent provides a simple way to integrate Over-the-Air updates into your app using Ardui...
static constexpr size_t OTA_BUFFER_SIZE
bool handle_noise_handshake_()
Drive the non-blocking handshake from loop(); returns true once the transport ciphers are ready.
ssize_t receive_data_(uint8_t *buf, DataTransfer &xfer)
bool would_block_(int error_code) const
uint32_t running_app_offset_
uint8_t handshake_buf_pos_
bool noise_write_(const uint8_t *data, size_t len)
Blocking write of a short response (at most NOISE_MAX_RESPONSE bytes) as one encrypted frame.
uint16_t get_port() const
static constexpr size_t SHA256_HEX_SIZE
static constexpr uint8_t MAGIC_BYTES[5]
bool udp_send_(const uint8_t *data, size_t len)
ota::OTAResponseTypes write_flash_(uint8_t *data, size_t len)
void yield_and_feed_watchdog_()
bool writeall_(const uint8_t *buf, size_t len)
bool try_read_(size_t to_read, const LogString *desc)
static constexpr bool ACK_AFTER_WRITE
static constexpr size_t OTA_INFLATE_WINDOW_SIZE
bool data_readall_(uint8_t *buf, size_t len)
static void udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, uint16_t port)
noise::NoiseContext noise_ctx_
ssize_t transport_read_(uint8_t *buf, size_t len)
void ack_written_(DataTransfer &xfer)
ssize_t noise_decrypt_(uint8_t *buf, size_t len)
Decrypt a ciphertext in place; returns the plaintext size or -1.
bool noise_readall_(uint8_t *buf, size_t len)
Blocking read of one frame whose plaintext must be exactly len bytes (control units are one unit per ...
bool noise_start_session_(uint8_t server_feature_flags)
Start the responder handshake, on the session reserved at offer time.
void set_noise_psk(const uint8_t *psk)
psk points at 32 bytes that live in flash for the life of the program
void set_auth_password(const std::string &password)
ota::OTABackendPtr backend_
bool try_write_(size_t to_write, const LogString *desc)
void dump_config() override
bool noise_try_read_frame_()
Non-blocking read of one handshake frame into the session buffer.
static constexpr size_t NOISE_CLIENT_MAX_PLAINTEXT
bool noise_offered_() const
RAMUniquePtr< NoiseSession > noise_
bool extended_proto_() const
bool handle_write_error_(ssize_t written, const LogString *desc)
ssize_t noise_read_frame_blocking_(uint8_t *buf, size_t min_ciphertext, size_t max_ciphertext)
Blocking read of one frame whose ciphertext size must be within the given bounds, decrypted in place;...
void send_chunk_acks_(DataTransfer &xfer)
bool data_write_byte_(uint8_t byte)
size_t noise_frame_payload_len_(const uint8_t *header, size_t min_len, size_t max_len)
Payload length from a frame header, or 0 (logged) when the indicator or the length is out of range.
void log_auth_warning_(const LogString *msg)
ssize_t udp_read_(uint8_t *buf, size_t len)
uint32_t client_connect_time_
RAMUniquePtr< InflateSession > inflate_
float get_setup_priority() const override
bool client_left_before_start_()
void send_error_and_cleanup_(ota::OTAResponseTypes error)
bool handle_read_error_(ssize_t read, const LogString *desc)
ssize_t noise_read_data_(uint8_t *buf, size_t capacity)
Blocking read of one data-phase frame, decrypted in place; returns the plaintext size,...
static constexpr uint8_t UDP_WINDOW
void log_read_error_(const LogString *what)
bool readall_(uint8_t *buf, size_t len)
bool data_write_(const uint8_t *data, size_t len)
void set_port(uint16_t port)
Manually set the port OTA should listen on.
void set_auth_password(const std::string &)
RAMUniquePtr< uint8_t[]> auth_buf_
void noise_send_reject_(const LogString *reason)
Best-effort explicit reject frame so the client can log a readable reason.
RAMUniquePtr< noise::psk_t > saved_psk_
void ack_received_(DataTransfer &xfer)
uint8_t handshake_buf_[HANDSHAKE_BUF_SIZE]
static constexpr size_t HANDSHAKE_BUF_SIZE
ota::OTAResponseTypes inflate_data_(uint8_t *in, size_t image_size, DataTransfer &xfer)
const noise::NoiseContext & noise_context_() const
void server_failed_(const LogString *msg)
void transition_ota_state_(OTAState next_state)
bool noise_try_write_frame_()
Non-blocking write of the pending session-buffer frame.
void cleanup_connection_()
bool read_size_(uint8_t *buf, size_t &size, const LogString *desc)
void noise_reserve_session_()
static void udp_on_datagram(UdpLink &link, UdpSlot p, uint16_t port)
socket::ListenSocket * server_
void log_remote_closed_(const LogString *during)
static constexpr size_t UDP_OUT_SIZE
std::unique_ptr< socket::Socket > client_
static void udp_send_ack(UdpLink &link, uint16_t prompted_by)
static constexpr size_t NOISE_MAX_RESPONSE
void udp_open_(UdpLink &link)
void log_start_(const LogString *phase)
ota::OTAResponseTypes inflate_flush_(InflateSession &session)
void log_socket_error_(const LogString *msg)
void set_psk(const uint8_t *psk)
psk points at 32 bytes that outlive the context (PROGMEM or caller owned RAM); nullptr means no key.
Sans-IO responder side of a Noise_NNpsk0_25519_ChaChaPoly_SHA256 handshake.
decltype(make_ota_backend()) OTABackendPtr
std::unique_ptr< T, RAMDeleter< T > > RAMUniquePtr
unique_ptr over RAMAllocator storage
uint16_t uint16_t & capacity
ESPHomeOTAComponent * self
uint8_t window[OTA_INFLATE_WINDOW_SIZE]
ota::OTAResponseTypes error
NoiseCipherState * recv_cipher
uint8_t frame_buf[noise::FRAME_HEADER_SIZE+1+noise::MAX_HANDSHAKE_SIZE]
NoiseCipherState * send_cipher
noise::NoiseResponderHandshake handshake
UdpSlot queue[UDP_WINDOW]
struct sockaddr_storage peer
std::unique_ptr< socket::Socket > sock
uint8_t out[UDP_OUT_SIZE]