fix(modem): Fixed OAT test to verify server cert and CN

This commit is contained in:
David Cermak
2023-11-27 20:04:04 +01:00
parent f2223dd719
commit edc3e7251f
14 changed files with 315 additions and 117 deletions

View File

@ -29,6 +29,7 @@ public:
int read(unsigned char *buf, size_t len);
[[nodiscard]] bool set_own_cert(const_buf crt, const_buf key);
[[nodiscard]] bool set_ca_cert(const_buf crt);
bool set_hostname(const char *name);
virtual int send(const unsigned char *buf, size_t len) = 0;
virtual int recv(unsigned char *buf, size_t len) = 0;
size_t get_available_bytes();

View File

@ -116,6 +116,16 @@ bool Tls::set_ca_cert(const_buf crt)
return true;
}
bool Tls::set_hostname(const char *name)
{
int ret = mbedtls_ssl_set_hostname(&ssl_, name);
if (ret < 0) {
print_error("mbedtls_ssl_set_hostname", ret);
return false;
}
return true;
}
Tls::Tls()
{
mbedtls_x509_crt_init(&public_cert_);

View File

@ -19,3 +19,9 @@ sudo pppd /dev/ttyUSB1 115200 192.168.11.1:192.168.11.2 ms-dns 8.8.8.8 modem loc
```
* MQTT broker: Running mosquitto in the default config is enough, configuring the broker's URL to the local PPP address: `config.broker.address.uri = "mqtt://192.168.11.1";`
* HTTP server: Need to support HTTP/1.1 (to support ranges). You can use the script `http_server.py` and configure the OTA endpoint as `"https://192.168.11.1:1234/esp32.bin"`
## Potential issues
When running this test it is expected to experience some buffer overflows or connection interruption.
The modem library should recover from these failure modes and continue and complete OTA update.
These issues are expected, since UART ISR is deliberately not placed into IRAM in the test configuration to exhibit some minor communication glitches.

Binary file not shown.

View File

@ -17,17 +17,9 @@ static const char *TAG = "manual_ota";
bool manual_ota::begin()
{
if (status != state::UNDEF) {
ESP_LOGE(TAG, "Invalid state");
ESP_LOGE(TAG, "Invalid state for manual_ota::perform");
return false;
}
status = state::INIT;
esp_transport_handle_t tcp = esp_transport_tcp_init();
ssl_ = esp_transport_batch_tls_init(tcp, max_buffer_size_);
esp_http_client_config_t config = { };
config.skip_cert_common_name_check = true;
config.url = uri_;
config.transport = ssl_;
const esp_partition_t *configured = esp_ota_get_boot_partition();
const esp_partition_t *running = esp_ota_get_running_partition();
@ -36,38 +28,40 @@ bool manual_ota::begin()
return false;
}
http_ = esp_http_client_init(&config);
if (http_ == nullptr) {
ESP_LOGE(TAG, "Failed to initialise HTTP connection");
return false;
}
esp_http_client_set_method(http_, HTTP_METHOD_HEAD);
esp_err_t err = esp_http_client_perform(http_);
if (err == ESP_OK) {
int http_status = esp_http_client_get_status_code(http_);
if (http_status != HttpStatus_Ok) {
ESP_LOGE(TAG, "Received incorrect http status %d", http_status);
return false;
status = state::INIT;
max_buffer_size_ = size_ * 1024;
if (mode_ == mode::BATCH) {
#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT
esp_transport_handle_t tcp = esp_transport_tcp_init();
ssl_ = esp_transport_batch_tls_init(tcp, max_buffer_size_);
http_.config_.transport = ssl_;
if (!esp_transport_batch_set_ca_cert(ssl_, http_.config_.cert_pem, 0)) {
return fail();
}
} else {
ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
if (!esp_transport_batch_set_cn(ssl_, common_name_)) {
return fail();
}
#else
ESP_LOGE(TAG, "mode::BATCH Cannot be used without CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT");
return false;
#endif
}
if (!http_.init()) {
return fail();
}
image_length_ = http_.get_image_len();
if (image_length_ <= 0) {
return fail();
}
image_length_ = esp_http_client_get_content_length(http_);
ESP_LOGI(TAG, "image_length = %lld", image_length_);
esp_http_client_close(http_);
if (image_length_ > size_) {
char *header_val = nullptr;
asprintf(&header_val, "bytes=0-%d", max_buffer_size_ - 1);
if (header_val == nullptr) {
ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
return false;
if (!http_.set_range(0, max_buffer_size_ - 1)) {
return fail();
}
esp_http_client_set_header(http_, "Range", header_val);
free(header_val);
}
esp_http_client_set_method(http_, HTTP_METHOD_GET);
esp_http_client_set_method(http_.handle_, HTTP_METHOD_GET);
partition_ = esp_ota_get_next_update_partition(nullptr);
if (partition_ == nullptr) {
@ -86,40 +80,42 @@ bool manual_ota::begin()
bool manual_ota::perform()
{
if (status != state::IMAGE_CHECK && status != state::START) {
ESP_LOGE(TAG, "Invalid state");
ESP_LOGE(TAG, "Invalid state for manual_ota::perform");
return false;
}
esp_err_t err = esp_http_client_open(http_, 0);
esp_err_t err = esp_http_client_open(http_.handle_, 0);
if (err != ESP_OK) {
if (image_length_ == file_length_) {
status = state::END;
return false;
}
esp_http_client_close(http_);
esp_http_client_close(http_.handle_);
ESP_LOGI(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
if (reconnect_attempts_++ < max_reconnect_attempts_) {
if (prepare_reconnect()) {
return true; // will retry in the next iteration
}
return true; // will retry in the next iteration
}
return fail_cleanup();
return fail();
}
esp_http_client_fetch_headers(http_);
esp_http_client_fetch_headers(http_.handle_);
int batch_len = esp_transport_batch_tls_pre_read(ssl_, max_buffer_size_, timeout_ * 1000);
if (batch_len < 0) {
ESP_LOGE(TAG, "Error: Failed to pre-read plain text data!");
return fail_cleanup();
int batch_len = max_buffer_size_;
if (mode_ == mode::BATCH) {
batch_len = esp_transport_batch_tls_pre_read(ssl_, max_buffer_size_, timeout_ * 1000);
if (batch_len < 0) {
ESP_LOGE(TAG, "Error: Failed to pre-read plain text data!");
fail();
return false;
}
}
int data_read = esp_http_client_read(http_, buffer_.data(), batch_len);
int data_read = esp_http_client_read(http_.handle_, buffer_.data(), batch_len);
if (data_read < 0) {
ESP_LOGE(TAG, "Error: SSL data read error");
return fail_cleanup();
return fail();
} else if (data_read > 0) {
esp_http_client_close(http_);
esp_http_client_close(http_.handle_);
if (status == state::IMAGE_CHECK) {
esp_app_desc_t new_app_info;
@ -146,7 +142,7 @@ bool manual_ota::perform()
ESP_LOGW(TAG, "New version is the same as invalid version.");
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
return fail_cleanup();
return fail();
}
}
@ -154,20 +150,18 @@ bool manual_ota::perform()
err = esp_ota_begin(partition_, OTA_WITH_SEQUENTIAL_WRITES, &update_handle_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
esp_ota_abort(update_handle_);
return fail_cleanup();
return fail();
}
ota_begin = true;
ESP_LOGI(TAG, "esp_ota_begin succeeded");
} else {
ESP_LOGE(TAG, "Received chunk doesn't contain app descriptor");
esp_ota_abort(update_handle_);
return fail_cleanup();
return fail();
}
}
err = esp_ota_write(update_handle_, (const void *)buffer_.data(), data_read);
if (err != ESP_OK) {
esp_ota_abort(update_handle_);
return fail_cleanup();
return fail();
}
file_length_ += data_read;
ESP_LOGI(TAG, "Written image length %d", file_length_);
@ -178,28 +172,22 @@ bool manual_ota::perform()
}
if (!prepare_reconnect()) {
esp_ota_abort(update_handle_);
return fail_cleanup();
return fail();
}
} else if (data_read == 0) {
if (file_length_ == 0) {
// Try to handle possible HTTP redirections
int status_code = esp_http_client_get_status_code(http_);
ESP_LOGW(TAG, "Status code: %d", status_code);
err = esp_http_client_set_redirection(http_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "URL redirection Failed");
esp_ota_abort(update_handle_);
return fail_cleanup();
if (!http_.handle_redirects()) {
return fail();
}
err = esp_http_client_open(http_, 0);
err = esp_http_client_open(http_.handle_, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
return fail_cleanup();
return fail();
}
esp_http_client_fetch_headers(http_);
esp_http_client_fetch_headers(http_.handle_);
}
}
@ -208,26 +196,13 @@ bool manual_ota::perform()
bool manual_ota::prepare_reconnect()
{
esp_http_client_set_method(http_, HTTP_METHOD_GET);
char *header_val = nullptr;
if ((image_length_ - file_length_) > max_buffer_size_) {
asprintf(&header_val, "bytes=%d-%d", file_length_, (file_length_ + max_buffer_size_ - 1));
} else {
asprintf(&header_val, "bytes=%d-", file_length_);
}
if (header_val == nullptr) {
ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
return false;
}
esp_http_client_set_header(http_, "Range", header_val);
free(header_val);
return true;
esp_http_client_set_method(http_.handle_, HTTP_METHOD_GET);
return http_.set_range(file_length_,
(image_length_ - file_length_) > max_buffer_size_ ? (file_length_ + max_buffer_size_ - 1) : 0);
}
bool manual_ota::fail_cleanup()
bool manual_ota::fail()
{
esp_http_client_close(http_);
esp_http_client_cleanup(http_);
status = state::FAIL;
return false;
}
@ -235,9 +210,9 @@ bool manual_ota::fail_cleanup()
bool manual_ota::end()
{
if (status == state::END) {
if (!esp_http_client_is_complete_data_received(http_)) {
if (!http_.is_data_complete()) {
ESP_LOGE(TAG, "Error in receiving complete file");
return fail_cleanup();
return fail();
}
esp_err_t err = esp_ota_end(update_handle_);
if (err != ESP_OK) {
@ -246,14 +221,97 @@ bool manual_ota::end()
} else {
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
}
return fail_cleanup();
return fail();
}
ota_begin = false;
err = esp_ota_set_boot_partition(partition_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
return fail_cleanup();
return fail();
}
return true;
}
return false;
}
manual_ota::~manual_ota()
{
if (ota_begin) {
esp_ota_abort(update_handle_);
}
}
bool manual_ota::http_client::handle_redirects()
{
int status_code = esp_http_client_get_status_code(handle_);
ESP_LOGW(TAG, "Status code: %d", status_code);
esp_err_t err = esp_http_client_set_redirection(handle_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "URL redirection Failed");
return false;
}
err = esp_http_client_open(handle_, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
return false;
}
esp_http_client_fetch_headers(handle_);
return true;
}
bool manual_ota::http_client::set_range(size_t from, size_t to)
{
char *header_val = nullptr;
if (to != 0) {
asprintf(&header_val, "bytes=%d-%d", from, to);
} else {
asprintf(&header_val, "bytes=%d-", from);
}
if (header_val == nullptr) {
ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
return false;
}
esp_http_client_set_header(handle_, "Range", header_val);
free(header_val);
return true;
}
bool manual_ota::http_client::is_data_complete()
{
return esp_http_client_is_complete_data_received(handle_);
}
manual_ota::http_client::~http_client()
{
if (handle_) {
esp_http_client_close(handle_);
esp_http_client_cleanup(handle_);
}
}
bool manual_ota::http_client::init()
{
handle_ = esp_http_client_init(&config_);
return handle_ != nullptr;
}
int64_t manual_ota::http_client::get_image_len()
{
esp_http_client_set_method(handle_, HTTP_METHOD_HEAD);
esp_err_t err = esp_http_client_perform(handle_);
if (err == ESP_OK) {
int http_status = esp_http_client_get_status_code(handle_);
if (http_status != HttpStatus_Ok) {
ESP_LOGE(TAG, "Received incorrect http status %d", http_status);
return -1;
}
} else {
ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
return -1;
}
int64_t image_length = esp_http_client_get_content_length(handle_);
ESP_LOGI(TAG, "image_length = %lld", image_length);
esp_http_client_close(handle_);
return image_length;
}

View File

@ -12,23 +12,57 @@
class manual_ota {
public:
enum class state {
UNDEF,
INIT,
IMAGE_CHECK,
START,
END,
FAIL,
};
/**
* @brief Set the preferred mode
*/
enum class mode {
BATCH, /**< Read data chunk from TCP and pass it to SSL, restore session on reconnection */
NORMAL /**< Use standard partial download, continuously passing data from TCP to mbedTLS */
} mode_ {mode::BATCH};
/**
* @brief Set the OTA batch size in kB
*
* This would allocate two big buffers:
* - one for reading from TCP socket and
* - one for passing to mbedTLS for description
*/
size_t size_{32};
/**
* @brief Set timeout in seconds
*
* This is the network timeout, so if less data than the batch size received
* the timeout (and no EOF) we should proceed with passing the data to mbedtls
*/
int timeout_{2};
/**
* @brief Construct a new manual ota object
*
* @param uri URI of the binary image
* @brief Set common name of the server to verify
*/
explicit manual_ota(const char *uri): uri_(uri) {}
const char *common_name_;
/**
* @brief Wrapper around the http client -- Please set the http config
*/
class http_client {
friend class manual_ota;
~http_client();
bool init();
esp_http_client_handle_t handle_{nullptr};
bool handle_redirects();
bool set_range(size_t from, size_t to);
bool is_data_complete();
int64_t get_image_len();
public:
esp_http_client_config_t config_{}; /**< Configure the http connection parameters */
} http_;
/**
* @brief Construct a new manual ota object
*/
explicit manual_ota() {}
~manual_ota();
/**
* @brief Start the manual OTA process
@ -53,11 +87,17 @@ public:
bool end();
private:
const char *uri_{};
esp_http_client_handle_t http_;
enum class state {
UNDEF,
INIT,
IMAGE_CHECK,
START,
END,
FAIL,
};
int64_t image_length_;
size_t file_length_;
const size_t max_buffer_size_{size_ * 1024};
size_t max_buffer_size_{size_ * 1024};
const esp_partition_t *partition_{nullptr};
state status{state::UNDEF};
std::vector<char> buffer_{};
@ -65,7 +105,8 @@ private:
const int max_reconnect_attempts_{3};
esp_transport_handle_t ssl_;
esp_ota_handle_t update_handle_{0};
bool ota_begin;
bool prepare_reconnect();
bool fail_cleanup();
bool fail();
};

View File

@ -12,7 +12,8 @@
class TlsTransport: public Tls {
public:
explicit TlsTransport(esp_transport_handle_t parent) : Tls(), transport_(parent), read_len(0), offset(0) {}
explicit TlsTransport(esp_transport_handle_t parent):
Tls(), transport_(parent), last_timeout(0), read_len(0), offset(0) {}
int send(const unsigned char *buf, size_t len) override;
int recv(unsigned char *buf, size_t len) override;
static bool set_func(esp_transport_handle_t tls_transport);
@ -40,11 +41,11 @@ private:
esp_transport_handle_t esp_transport_tls_init(esp_transport_handle_t parent)
{
esp_transport_handle_t ssl = esp_transport_init();
auto *tls = new TlsTransport(parent);
esp_transport_set_context_data(ssl, tls);
TlsTransport::set_func(ssl);
return ssl;
esp_transport_handle_t transport_handle = esp_transport_init();
auto *tls_context = new TlsTransport(parent);
esp_transport_set_context_data(transport_handle, tls_context);
TlsTransport::set_func(transport_handle);
return transport_handle;
}
int TlsTransport::send(const unsigned char *buf, size_t len)
@ -105,7 +106,7 @@ void TlsTransport::delay()
int TlsTransport::transport::connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
{
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t));
tls->init(is_server{false}, do_verify{false});
tls->init(is_server{false}, do_verify{true});
ESP_LOGD(TAG, "TLS-connect");
auto ret = tls->connect(host, port, timeout_ms);
@ -122,7 +123,10 @@ int TlsTransport::transport::connect(esp_transport_handle_t t, const char *host,
ESP_LOGI(TAG, "Failed to handshake");
return ret;
}
tls->get_session();
if (!tls->get_session()) {
// we're not able to save session, report an error and continue (next connection will be slower)
ESP_LOGW(TAG, "Failed to save session");
}
ESP_LOGI(TAG, "After handshake");
return 0;
}
@ -202,6 +206,19 @@ esp_transport_handle_t esp_transport_batch_tls_init(esp_transport_handle_t paren
return ssl;
}
bool esp_transport_batch_set_ca_cert(esp_transport_handle_t t, const char *ca_cert, size_t cert_len = 0)
{
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t));
const_buf cert((const unsigned char *)ca_cert, cert_len ? cert_len : strlen(ca_cert) + 1);
return tls->set_ca_cert(cert);
}
bool esp_transport_batch_set_cn(esp_transport_handle_t t, const char *name)
{
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t));
return tls->set_hostname(name);
}
int TlsTransport::preread(size_t len, int timeout_ms)
{
while (len != read_len) {
@ -225,7 +242,7 @@ bool TlsTransport::prepare_buffer(size_t max_size)
return true;
}
int esp_transport_batch_tls_pre_read(esp_transport_handle_t t, int len, int timeout_ms)
int esp_transport_batch_tls_pre_read(esp_transport_handle_t t, size_t len, int timeout_ms)
{
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t));
return tls->preread(len, timeout_ms);

View File

@ -22,4 +22,22 @@ esp_transport_handle_t esp_transport_batch_tls_init(esp_transport_handle_t paren
* @param timeout_ms Timeout in ms
* @return true If read from the parent transport completed successfully
*/
bool esp_transport_batch_tls_pre_read(esp_transport_handle_t t, int len, int timeout_ms);
bool esp_transport_batch_tls_pre_read(esp_transport_handle_t t, size_t len, int timeout_ms);
/**
* @brief Set the CA Certificate to verify the server
*
* @param ca_cert Pointer to the CA Cert data
* @param cert_len CA Cert data len (set to 0 if null terminated string, i.e. PEM format)
* @return true on success
*/
bool esp_transport_batch_set_ca_cert(esp_transport_handle_t t, const char *ca_cert, size_t cert_len);
/**
* @brief Set comman name
* @param t
* @param ca_cert
* @param cert_len
* @return
*/
bool esp_transport_batch_set_cn(esp_transport_handle_t t, const char *name);

View File

@ -38,6 +38,19 @@ menu "Test Configuration"
help
HTTPS address of the update binary.
config TEST_OTA_CA_CERT
string "Server certificate"
default "---paste the server side certificate here---"
help
Insert the CA cert of the server side here. copy the base64 text between -----BEGIN CERTIFICATE-----
and -----END CERTIFICATE-----.
config TEST_OTA_CN
string "Server common name"
default "192.168.11.1"
help
Insert the server's common name to be checked within verification of the Server side certificat
config BROKER_URI
string "Broker URL"
default "mqtt://test.mosquitto.org"

View File

@ -50,7 +50,9 @@ public:
void remove_mqtt()
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
esp_mqtt_client_unregister_event(mqtt, MQTT_EVENT_ANY, on_event);
#endif
mqtt = nullptr;
}
@ -145,9 +147,17 @@ static constexpr auto OTA_FAILED = SignalGroup::bit1;
void ota_task(void *ctx)
{
static const char *ca_cert_pem = "-----BEGIN CERTIFICATE-----\n" CONFIG_TEST_OTA_CA_CERT "\n-----END CERTIFICATE-----";
auto ota_done = static_cast<esp_modem::SignalGroup *>(ctx);
manual_ota ota(CONFIG_TEST_OTA_URI);
ota.size_ = 64;
manual_ota ota;
ota.http_.config_.url = CONFIG_TEST_OTA_URI;
ota.http_.config_.cert_pem = ca_cert_pem;
ota.size_ = 32;
ota.common_name_ = CONFIG_TEST_OTA_CN;
#ifndef CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT
// will have to use NORMAL mode, before custom transport is supported in IDF
ota.mode_ = manual_ota::mode::NORMAL;
#endif
ota.begin();
while (true) {
@ -253,11 +263,13 @@ extern "C" void app_main(void)
esp_modem::SignalGroup ota_done{};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
// now stop the LCP keepalive before performing OTA
esp_netif_ppp_config_t cfg;
ESP_ERROR_CHECK(esp_netif_ppp_get_params(esp_netif, &cfg));
cfg.ppp_lcp_echo_disabled = true;
ESP_ERROR_CHECK(esp_netif_ppp_set_params(esp_netif, &cfg));
#endif
// Run the OTA in a separate task to keep sending commands to the modem at the same time
xTaskCreate(ota_task, "ota_task", 8192, &ota_done, 5, nullptr);

View File

@ -0,0 +1,2 @@
CONFIG_TEST_DEVICE_PPPD_SERVER=y
CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD=n

View File

@ -0,0 +1,4 @@
CONFIG_TEST_DEVICE_MODEM_GENERIC=y
CONFIG_TEST_OTA_URI="https://raw.githubusercontent.com/espressif/esp-protocols/master/components/esp_modem/test/target_ota/bin/blink.bin"
CONFIG_TEST_OTA_CA_CERT="MIIEvjCCA6agAwIBAgIQBtjZBNVYQ0b2ii+nVCJ+xDANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBSU0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6aqXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddng9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuWraKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGBAfr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21reacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBgjCCAX4wEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUt2ui6qiqhIx56rTaD5iyxZV2ufQwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwCwYJYIZIAYb9bAIBMAcGBWeBDAEBMAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IBAQCAMs5eC91uWg0Kr+HWhMvAjvqFcO3aXbMM9yt1QP6FCvrzMXi3cEsaiVi6gL3zax3pfs8LulicWdSQ0/1s/dCYbbdxglvPbQtaCdB73sRD2Cqk3p5BJl+7j5nL3a7hqG+fh/50tx8bIKuxT8b1Z11dmzzp/2n3YWzW2fP9NsarA4h20ksudYbj/NhVfSbCEXffPgK2fPOre3qGNm+499iTcc+G33Mw+nur7SpZyEKEOxEXGlLzyQ4UfaJbcme6ce1XR2bFuAJKZTRei9AqPCCcUZlM51Ke92sRKw2Sfh3oius2FkOH6ipjv3U/697EA7sKPPcw7+uvTPyLNhBzPvOk"
CONFIG_TEST_OTA_CN="github.com"

View File

@ -0,0 +1,4 @@
CONFIG_TEST_DEVICE_PPPD_SERVER=y
CONFIG_ESP_MODEM_CMUX_DEFRAGMENT_PAYLOAD=y
CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED=y
CONFIG_TEST_USE_VFS_TERM=y

View File

@ -0,0 +1,12 @@
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_TWO_OTA=y
CONFIG_COMPILER_CXX_EXCEPTIONS=y
# This is not supported in IDF yet
# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT=y
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
CONFIG_LWIP_PPP_SUPPORT=y
CONFIG_LWIP_PPP_ENABLE_IPV6=n
CONFIG_LWIP_ENABLE_LCP_ECHO=y
CONFIG_LWIP_LCP_ECHOINTERVAL=1
CONFIG_LWIP_LCP_MAXECHOFAILS=2