Im not able to establish internet via pppos protocol on ec200u-cn embedded with esp32s3 dev

Hi everyone ,
im facing a trouble establishing internet via pppos protocol with the jio sim of ipv6 only supported doing it using libraries and no manual at commands as they completely work , since i started this on the arduino ide where there is no specific defines or modem listed on arduino for the ec200cn so i used the bg96 since the arduino libraries doesnt support ipv6 (tinygsm) i switched to esp-idf v4.4 py.v3.9 manually cloned .
So the problem is im not able to get the ipv6 ip and the ppp internet is not establishing , and not able to ping and website like google, youtube..com , and i also reffered this example but i could’t make it .

Im literellt stuck in this please help me with this ,
Attaching the modem and output .
kindy see through .

// main/pppos_client_main.c
// ESP32-S3 + Quectel EC200U (BG96 driver) + PPPoS + Google “ping” via HTTP
// Pins: TX=37, RX=36, baud 115200, APN=jionet, PDP type IPV4V6.

#include <string.h>
#include <stdio.h>

#include “freertos/FreeRTOS.h”
#include “freertos/event_groups.h”
#include “freertos/task.h”

#include “esp_system.h”
#include “esp_log.h”

#include “esp_netif.h”
#include “esp_netif_ppp.h”

#include “mqtt_client.h” // not strictly needed, but kept from example
#include “esp_modem.h”
#include “esp_modem_netif.h”
#include “bg96.h”

#include “lwip/sockets.h”
#include “lwip/netdb.h”

static const char *TAG = “pppos_ec200u”;

static EventGroupHandle_t event_group;
static const int CONNECT_BIT = BIT0;
static const int STOP_BIT = BIT1;

// ---------- board + SIM settings ----------
#define MODEM_TX_PIN 37
#define MODEM_RX_PIN 36
#define MODEM_BAUD 115200
#define MODEM_APN “jionet” // Jio
#define MODEM_PDP_TYPE “IPV4V6” // allow v4+v6 on the PDN
// -----------------------------------------

// =============== PPP / modem event handlers =================

static void modem_event_handler(void *arg,
esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
switch (event_id) {
case ESP_MODEM_EVENT_PPP_START:
ESP_LOGI(TAG, “Modem PPP Started”);
break;
case ESP_MODEM_EVENT_PPP_STOP:
ESP_LOGI(TAG, “Modem PPP Stopped”);
xEventGroupSetBits(event_group, STOP_BIT);
break;
case ESP_MODEM_EVENT_UNKNOWN:
ESP_LOGW(TAG, “Unknown modem line: %s”, (char *)event_data);
break;
default:
break;
}
}

static void on_ppp_status_changed(void *arg,
esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
ESP_LOGI(TAG, “PPP state changed event: %d”, event_id);
}

// IP events: IPv4 and IPv6
static void on_ip_event(void *arg,
esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
if (event_id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *e = (ip_event_got_ip_t *)event_data;
esp_netif_dns_info_t dns;
ESP_LOGI(TAG, “PPP GOT IPv4:”);
ESP_LOGI(TAG, " IP : " IPSTR, IP2STR(&e->ip_info.ip));
ESP_LOGI(TAG, " Netmask : " IPSTR, IP2STR(&e->ip_info.netmask));
ESP_LOGI(TAG, " Gateway : " IPSTR, IP2STR(&e->ip_info.gw));
esp_netif_get_dns_info(e->esp_netif, 0, &dns);
ESP_LOGI(TAG, " DNS1 : " IPSTR, IP2STR(&dns.ip.u_addr.ip4));
esp_netif_get_dns_info(e->esp_netif, 1, &dns);
ESP_LOGI(TAG, " DNS2 : " IPSTR, IP2STR(&dns.ip.u_addr.ip4));
xEventGroupSetBits(event_group, CONNECT_BIT);
} else if (event_id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *e6 = (ip_event_got_ip6_t *)event_data;
ESP_LOGI(TAG, "PPP GOT IPv6: " IPV6STR, IPV62STR(e6->ip6_info.ip));
xEventGroupSetBits(event_group, CONNECT_BIT);
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
ESP_LOGI(TAG, “PPP lost IP”);
}
}

// =============== simple “ping” using sockets =================

// Resolve /www.google.com and open TCP connection on port 80.
// This proves: DNS works + routing works (over IPv4 or IPv6).
static void test_google_http(void)
{
const char *host = “/www.google.com”;
const char *port = “80”;

struct addrinfo hints = { 0 };
hints.ai_family   = AF_UNSPEC;     // allow IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM;

struct addrinfo *res = NULL;
int err = getaddrinfo(host, port, &hints, &res);
if (err != 0 || res == NULL) {
    ESP_LOGE(TAG, "getaddrinfo(%s) failed: %d", host, err);
    return;
}

ESP_LOGI(TAG, "Resolved %s, trying addresses:", host);
for (struct addrinfo *p = res; p != NULL; p = p->ai_next) {
    char addrstr[64];
    void *addr = NULL;
    if (p->ai_family == AF_INET) {
        struct sockaddr_in *sa = (struct sockaddr_in *)p->ai_addr;
        addr = &sa->sin_addr;
    } else if (p->ai_family == AF_INET6) {
        struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)p->ai_addr;
        addr = &sa6->sin6_addr;
    }
    if (addr) {
        inet_ntop(p->ai_family, addr, addrstr, sizeof(addrstr));
        ESP_LOGI(TAG, "  %s", addrstr);
    }
}

// Use the first result
int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0) {
    ESP_LOGE(TAG, "socket() failed");
    freeaddrinfo(res);
    return;
}

ESP_LOGI(TAG, "Connecting to %s:%s ...", host, port);
if (connect(s, res->ai_addr, res->ai_addrlen) != 0) {
    ESP_LOGE(TAG, "connect() failed, errno=%d", errno);
    close(s);
    freeaddrinfo(res);
    return;
}

ESP_LOGI(TAG, "TCP connect OK – internet reachable.");

const char *req = "HEAD / HTTP/1.0\r\nHost: www.google.com\r\n\r\n";
send(s, req, strlen(req), 0);

char buf[256];
int r = recv(s, buf, sizeof(buf) - 1, 0);
if (r > 0) {
    buf[r] = 0;
    ESP_LOGI(TAG, "HTTP response (first bytes):\n%.*s", r, buf);
} else {
    ESP_LOGW(TAG, "No data received from google");
}

close(s);
freeaddrinfo(res);

}

// ======================= APP MAIN ============================

void app_main(void)
{
// — basic ESP-NETIF + events —
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT,
ESP_EVENT_ANY_ID,
&on_ip_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS,
ESP_EVENT_ANY_ID,
&on_ppp_status_changed, NULL));

event_group = xEventGroupCreate();

// --- create DTE (UART side of modem) ---
esp_modem_dte_config_t cfg = ESP_MODEM_DTE_DEFAULT_CONFIG();
cfg.tx_io_num            = MODEM_TX_PIN;
cfg.rx_io_num            = MODEM_RX_PIN;
cfg.rx_buffer_size       = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE;
cfg.tx_buffer_size       = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE;
cfg.event_queue_size     = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE;
cfg.event_task_stack_size= CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE;
cfg.event_task_priority  = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY;
cfg.dte_buffer_size      = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE / 2;

ESP_LOGI(TAG, "Creating DTE: TX=%d RX=%d BAUD=%d",
         MODEM_TX_PIN, MODEM_RX_PIN, MODEM_BAUD);

modem_dte_t *dte = esp_modem_dte_init(&cfg);
if (!dte) {
    ESP_LOGE(TAG, "esp_modem_dte_init failed");
    return;
}
ESP_ERROR_CHECK(esp_modem_set_event_handler(dte, modem_event_handler,
                                            ESP_EVENT_ANY_ID, NULL));

// --- create DCE (BG96 driver, works for EC200U) ---
modem_dce_t *dce = bg96_init(dte);
if (!dce) {
    ESP_LOGE(TAG, "bg96_init failed");
    return;
}

// make sure we are not using HW flow control; EC200U board has only TX/RX
esp_err_t fl = dce->set_flow_ctrl(dce, MODEM_FLOW_CONTROL_NONE);
if (fl != ESP_OK) {
    ESP_LOGW(TAG, "set_flow_ctrl failed: %s", esp_err_to_name(fl));
}

// define PDP context as IPv4v6 + APN=jionet
ESP_LOGI(TAG, "Setting PDP context CID=1, type=%s, APN=%s",
         MODEM_PDP_TYPE, MODEM_APN);
if (dce->define_pdp_context) {
    esp_err_t pdp = dce->define_pdp_context(dce, 1,
                                            MODEM_PDP_TYPE, MODEM_APN);
    if (pdp != ESP_OK) {
        ESP_LOGW(TAG, "define_pdp_context failed: %s",
                 esp_err_to_name(pdp));
    }
}

ESP_ERROR_CHECK(dce->store_profile(dce));

ESP_LOGI(TAG, "Module: %s", dce->name);
ESP_LOGI(TAG, "Operator: %s", dce->oper);
ESP_LOGI(TAG, "IMEI: %s",    dce->imei);
ESP_LOGI(TAG, "IMSI: %s",    dce->imsi);

uint32_t rssi = 0, ber = 0;
ESP_ERROR_CHECK(dce->get_signal_quality(dce, &rssi, &ber));
ESP_LOGI(TAG, "Signal rssi=%d, ber=%d", rssi, ber);

// --- create PPP netif and attach modem ---
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_PPP();
esp_netif_t *ppp_netif = esp_netif_new(&netif_cfg);
assert(ppp_netif);

#if !defined(CONFIG_EXAMPLE_MODEM_PPP_AUTH_NONE) &&
(defined(CONFIG_LWIP_PPP_PAP_SUPPORT) || defined(CONFIG_LWIP_PPP_CHAP_SUPPORT))
esp_netif_auth_type_t auth_type =
#if CONFIG_LWIP_PPP_PAP_SUPPORT
NETIF_PPP_AUTHTYPE_PAP;
#else
NETIF_PPP_AUTHTYPE_CHAP;
#endif
esp_netif_ppp_set_auth(ppp_netif, auth_type,
CONFIG_EXAMPLE_MODEM_PPP_AUTH_USERNAME,
CONFIG_EXAMPLE_MODEM_PPP_AUTH_PASSWORD);
#endif

void *modem_netif_adapter = esp_modem_netif_setup(dte);
esp_modem_netif_set_default_handlers(modem_netif_adapter, ppp_netif);
esp_netif_attach(ppp_netif, modem_netif_adapter);
// default handlers will start PPP when attached

ESP_LOGI(TAG, "Waiting for PPP to get IP (IPv4 or IPv6)...");
xEventGroupWaitBits(event_group, CONNECT_BIT,
                    pdTRUE, pdTRUE, portMAX_DELAY);

ESP_LOGI(TAG, "PPP connected – running Google HTTP test");
test_google_http();

// keep link alive for a while so you can watch traffic
vTaskDelay(pdMS_TO_TICKS(30000));

ESP_LOGI(TAG, "Stopping PPP");
ESP_ERROR_CHECK(esp_modem_stop_ppp(dte));
xEventGroupWaitBits(event_group, STOP_BIT, pdTRUE, pdTRUE, portMAX_DELAY);

ESP_ERROR_CHECK(dce->power_down(dce));
ESP_LOGI(TAG, "Modem powered down");

// cleanup (normally you’d loop and reconnect instead of destroying)
esp_modem_netif_clear_default_handlers(modem_netif_adapter);
esp_modem_netif_teardown(modem_netif_adapter);
esp_netif_destroy(ppp_netif);
ESP_ERROR_CHECK(dce->deinit(dce));
ESP_ERROR_CHECK(dte->deinit(dte));

}

Idf-monitor output
I (25) boot: ESP-IDF v4.4 2nd stage bootloader
I (25) boot: compile time 00:11:14
I (25) boot: chip revision: 0
I (26) boot.esp32s3: Boot SPI Speed : 80MHz
I (31) boot.esp32s3: SPI Mode : DIO
I (36) boot.esp32s3: SPI Flash Size : 2MB
I (40) boot: Enabling RNG early entropy source…
I (46) boot: Partition Table:
I (49) boot: ## Label Usage Type ST Offset Length
I (57) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (64) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (72) boot: 2 factory factory app 00 00 00010000 00100000
I (79) boot: End of partition table
I (83) esp_image: segment 0: paddr=00010020 vaddr=3c050020 size=148f8h ( 84216) map
I (107) esp_image: segment 1: paddr=00024920 vaddr=3fc91c60 size=026a0h ( 9888) load
I (109) esp_image: segment 2: paddr=00026fc8 vaddr=40374000 size=09050h ( 36944) load
I (121) esp_image: segment 3: paddr=00030020 vaddr=42000020 size=4b344h (308036) map
I (176) esp_image: segment 4: paddr=0007b36c vaddr=4037d050 size=04c08h ( 19464) load
I (181) esp_image: segment 5: paddr=0007ff7c vaddr=50000000 size=00010h ( 16) load
I (188) boot: Loaded app from partition at offset 0x10000
I (188) boot: Disabling RNG early entropy source…
I (205) cpu_start: Pro cpu up.
I (205) cpu_start: Starting app cpu, entry point is 0x403751f8
0x403751f8: call_start_cpu1 at D:/ESPIDF_V4/esp-idf-v4.4/components/esp_system/port/cpu_start.c:156

I (0) cpu_start: App cpu up.
I (219) cpu_start: Pro cpu start user code
I (219) cpu_start: cpu freq: 160000000
I (219) cpu_start: Application information:
I (222) cpu_start: Project name: pppos_client
I (227) cpu_start: App version: 1
I (232) cpu_start: Compile time: Dec 2 2025 00:11:00
I (238) cpu_start: ELF file SHA256: 0a68f54ffd381935…
I (244) cpu_start: ESP-IDF: v4.4
I (249) heap_init: Initializing. RAM available for dynamic allocation:
I (256) heap_init: At 3FC95CE0 len 0004A320 (296 KiB): D/IRAM
I (262) heap_init: At 3FCE0000 len 0000EE34 (59 KiB): STACK/DRAM
I (269) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (275) heap_init: At 600FE000 len 00002000 (8 KiB): RTCRAM
I (282) spi_flash: detected chip: generic
I (286) spi_flash: flash io: dio
W (290) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (304) sleep: Configure to isolate all GPIO pins in sleep state
I (310) sleep: Enable automatic switching of GPIO sleep configuration
I (317) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (338) pppos_ec200u: Creating DTE: TX=37 RX=36 BAUD=115200
I (338) uart: queue free spaces: 30
I (448) pppos_ec200u: Setting PDP context CID=1, type=IPV4V6, APN=jionet
I (498) pppos_ec200u: Module: EC200U
I (498) pppos_ec200u: Operator: “IND-JIO”
I (498) pppos_ec200u: IMEI: 868019065934094
I (498) pppos_ec200u: IMSI: 405861708127248
I (518) pppos_ec200u: Signal rssi=22, ber=99
ppp phase changed[1]: phase=0
I (568) pppos_ec200u: Waiting for PPP to get IP (IPv4 or IPv6)…
I (668) pppos_ec200u: Modem PPP Started
ppp_connect[1]: holdoff=0
ppp phase changed[1]: phase=3
I (668) pppos_ec200u: PPP state changed event: 259
pppos_connect: unit 1: connecting
ppp_start[1]
ppp phase changed[1]: phase=6
I (678) pppos_ec200u: PPP state changed event: 262
pppos_send_config[1]: out_accm=FF FF FF FF
ppp_send_config[1]
pppos_recv_config[1]: in_accm=FF FF FF FF
ppp_recv_config[1]
ppp: auth protocols: PAP=1 CHAP=0 CHAP_MD5=0 CHAP_MS=0 CHAP_MS2=0
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x670a05ad> ]
pppos_write[1]: len=24
ppp_start[1]: finished
pppos_input[1]: got 53 bytes
rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x86cd83f3> ]
sent [LCP ConfNak id=0x1 ]
pppos_write[1]: len=12
pppos_input[1]: got 47 bytes
rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0x670a05ad> ]
pppos_input[1]: got 51 bytes
rcvd [LCP ConfReq id=0x2 <asyncmap 0x0> <magic 0x86cd83f3> ]
sent [LCP ConfAck id=0x2 <asyncmap 0x0> <magic 0x86cd83f3> ]
pppos_write[1]: len=28
netif_set_mtu[1]: mtu=1500
pppos_send_config[1]: out_accm=0 0 0 0
ppp_send_config[1]
pppos_recv_config[1]: in_accm=0 0 0 0
ppp_recv_config[1]
sent [LCP EchoReq id=0x0 magic=0x670a05ad]
pppos_write[1]: len=12
ppp phase changed[1]: phase=7
I (798) pppos_ec200u: PPP state changed event: 263
sent [PAP AuthReq id=0x1 user=“espressif” password=“esp32”]
pppos_write[1]: len=24
pppos_input[1]: got 16 bytes
rcvd [LCP EchoRep id=0x0 magic=0x86cd83f3]
pppos_input[1]: got 21 bytes
rcvd [PAP AuthAck id=0x1 “Login ok”]
Remote message: Login ok
PAP authentication succeeded
ppp phase changed[1]: phase=9
I (848) pppos_ec200u: PPP state changed event: 265
ccp_set[1]: is_open=1, is_up=0, receive_method=0, transmit_method=0
sent [IPCP ConfReq id=0x1 <compress VJ 0f 01> <addr 0.0.0.0> <ms-dns1 0.0.0.0> <ms-dns2 0.0.0.0>]
pppos_write[1]: len=32
sent [IPV6CP ConfReq id=0x1 ]
pppos_write[1]: len=18
pppos_input[1]: got 12 bytes
rcvd [IPCP ConfReq id=0x1]
sent [IPCP ConfNak id=0x1 <addr 0.0.0.0>]
pppos_write[1]: len=14
pppos_input[1]: got 46 bytes
rcvd [IPCP ConfRej id=0x1 <compress VJ 0f 01> <ms-dns2 0.0.0.0>]
sent [IPCP ConfReq id=0x2 <addr 0.0.0.0> <ms-dns1 0.0.0.0>]
pppos_write[1]: len=20
rcvd [IPV6CP ConfReq id=0x1 ]
sent [IPV6CP ConfAck id=0x1 ]
pppos_write[1]: len=18
pppos_input[1]: got 22 bytes
rcvd [IPV6CP ConfAck id=0x1 ]
sif6up[1]: err_code=0
I (948) esp-netif_lwip-ppp: Connected
I (948) esp-netif_lwip-ppp: Got IPv6 address fe80:0000:0000:0000:68ba:d339:4dd4:73e1
I (958) pppos_ec200u: PPP GOT IPv6: fe80:0000:0000:0000:68ba:d339:4dd4:73e1
local LL address fe80::68ba:d339:4dd4:73e1
I (968) pppos_ec200u: PPP connected – running Google HTTP test
remote LL address fe80::1415:532b:2cd2:d282
ppp phase changed[1]: phase=10
I (978) pppos_ec200u: PPP state changed event: 266
pppos_input[1]: got 18 bytes
rcvd [IPCP ConfReq id=0x2 <addr 192.168.0.1>]
sent [IPCP ConfAck id=0x2 <addr 192.168.0.1>]
pppos_write[1]: len=14
pppos_input[1]: got 25 bytes
rcvd [IPCP ConfNak id=0x2 <addr 10.3.126.206> <ms-dns1 49.45.0.1>]
sent [IPCP ConfReq id=0x3 <addr 10.3.126.206> <ms-dns1 49.45.0.1>]
pppos_write[1]: len=20
E (1018) pppos_ec200u: getaddrinfo(/www.google.com) failed: 202
pppos_input[1]: got 25 bytes
rcvd [IPCP ConfAck id=0x3 <addr 10.3.126.206> <ms-dns1 49.45.0.1>]
sifvjcomp[1]: VJ compress enable=0 slot=0 max slot=0
sifup[1]: err_code=0
I (1058) esp-netif_lwip-ppp: Connected
I (1058) esp-netif_lwip-ppp: Name Server1: 49.45.0.1
I (1068) esp-netif_lwip-ppp: Name Server2: 0.0.0.0
I (1068) pppos_ec200u: PPP GOT IPv4:
I (1078) pppos_ec200u: IP : 10.3.126.206
local IP address 10.3.126.206
I (1078) pppos_ec200u: Netmask : 255.255.255.255
remote IP address 192.168.0.1
primary DNS address 49.45.0.1
I (1088) pppos_ec200u: Gateway : 192.168.0.1
I (1098) pppos_ec200u: DNS1 : 49.45.0.1
I (1098) pppos_ec200u: DNS2 : 0.0.0.0
pppos_netif_output[1]: proto=0x57, len = 56
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_netif_output[1]: proto=0x57, len = 56
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_netif_output[1]: proto=0x57, len = 56
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
pppos_write[1]: len=12
pppos_input[1]: got 16 bytes
I (31018) pppos_ec200u: Stopping PPP
E (32928) esp-modem: handle line failed
I (32928) pppos_ec200u: Modem PPP Stopped
ppp_close[1]: kill_link → lcp_close
ppp phase changed[1]: phase=11
I (32938) pppos_ec200u: PPP state changed event: 267
sifvjcomp[1]: VJ compress enable=0 slot=0 max slot=0
sifdown[1]: err_code=5
ppp phase changed[1]: phase=9
I (32948) pppos_ec200u: PPP state changed event: 265
sif6down[1]: err_code=5
ccp_set[1]: is_open=0, is_up=0, receive_method=0, transmit_method=0
ppp phase changed[1]: phase=6
I (32968) pppos_ec200u: PPP state changed event: 262
pppos_send_config[1]: out_accm=FF FF FF FF
ppp_send_config[1]
pppos_recv_config[1]: in_accm=0 0 0 0
ppp_recv_config[1]
sent [LCP TermReq id=0x2 “User request”]
pppos_write[1]: len=20
W (33088) pppos_ec200u: Unknown modem line: ~�}#�!}%}#} }0User requesty{~
sent [LCP TermReq id=0x3 “User request”]
pppos_write[1]: len=20
ppp phase changed[1]: phase=12
I (44988) pppos_ec200u: PPP state changed event: 268
Connection terminated.
ppp_link_terminated[1]
ppp_link_end[1]
ppp phase changed[1]: phase=0
I (44988) pppos_ec200u: PPP state changed event: 256
I (44998) esp-netif_lwip-ppp: User interrupt
I (44998) pppos_ec200u: PPP state changed event: 5
I (45008) esp-modem-netif: PPP state changed event 5
ppp_link_terminated[1]: finished.
I (45698) pppos_ec200u: Modem powered down
ppp_free[1]

Thank you
vignesh sai

Hi Vignesh,

Thanks for providing all the details and logs. I went through your setup and here are my observations and suggestions:

Your PPP connection does start and the modem establishes a link:

I (668) pppos_ec200u: PPP state changed event: 262

You are getting an IPv6 link-local address (fe80::68ba:d339:4dd4:73e1) but no global IPv6, which is required for internet access.

IPv4 is also assigned (10.3.126.206), but this is not useful since the Jio APN (jionet) is IPv6-only.

DNS resolution fails over PPP:

E (1018) pppos_ec200u: getaddrinfo(/www.google.com) failed: 202

This indicates that IPv6 routing or DNS is not configured properly.

Eventually, PPP disconnects, which is expected when no traffic can route correctly. ESP-IDF v4.4 PPP stack has limited IPv6 support. It can bring up a link-local IPv6, but global IPv6 addresses and DNS over PPP may not work fully.

Your current PDP context “IPV4V6” is causing IPv4 IPCP negotiation alongside IPv6CP. Since Jio’s APN only provides IPv6, this can confuse PPP negotiation.

Some Jio APNs do not provide DNS automatically over IPv6, so manual DNS configuration may be needed.

Suggested actions:

-Change PDP type to IPv6 only:

#define MODEM_PDP_TYPE “IPV6”

This avoids conflicts with IPv4 IPCP negotiation.

Check DNS over IPv6:

After PPP connects, verify IPv6 DNS is assigned. If not, set it manually:

esp_netif_set_dns_info(ppp_netif, ESP_NETIF_DNS_MAIN, &(esp_netif_dns_info_t){
.ip = {.type = ESP_IP6_ADDR, .u_addr.ip6 = {0x2001,0x4860,0x4860,0,0,0,0,0x8888}}
});

(Google public IPv6 DNS is 2001:4860:4860::8888.)

Verify global IPv6 via AT commands first:

AT+CGDCONT=1,“IPV6”,“jionet”
AT+CGACT=1,1
AT+CGPADDR=1

You should see a global IPv6 address from Jio.

Consider upgrading ESP-IDF to v5.x, which has better PPP IPv6 support, or switching to QMI/MBIM instead of PPP for IPv6-only networks.

Have a great day!

Best Regards,
Ananthan

Thank you ananthan for your briefs , helped alot.
I tried forcing the ipv6 pdp and also got the ipv6 IP globally but could’nt able to establish the pppos internet and the Dialing ATD99**1# got me connect which seem its on the data mode, but the (I (12087) PPPOS_ONLY: Calling pppapi_connect… ) did not result any ip and the pppos failed, Can you please help me with the firmware.
Attaching the output logs and the present firmware.
Kindly consider.

#include <string.h>
#include <stdio.h>

#include “freertos/FreeRTOS.h”
#include “freertos/task.h”

#include “driver/uart.h”
#include “driver/gpio.h”

#include “netif/ppp/pppapi.h”
#include “netif/ppp/pppos.h”
#include “netif/ppp/ppp.h”
#include “lwip/netif.h”
#include “lwip/sockets.h”
#include “lwip/inet.h”

#include “esp_log.h”
#include “esp_event.h”
#include “esp_netif.h”

#define MODEM_UART UART_NUM_1
#define UART_TX_PIN 37
#define UART_RX_PIN 36
#define UART_BAUDRATE 115200
#define MODEM_PWRKEY 1
#define APN “jionet”
#define MODEM_PDP_TYPE “IPV6” // IPv6-only as suggested

static const char *TAG = “PPPOS_ONLY”;
static ppp_pcb *ppp;
static struct netif ppp_netif;
static esp_netif_t *esp_netif_ppp;

/* UART init */
static void uart_init(void)
{
uart_config_t cfg = {
.baud_rate = UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_driver_install(MODEM_UART, 4096, 4096, 0, NULL, 0);
uart_param_config(MODEM_UART, &cfg);
uart_set_pin(MODEM_UART, UART_TX_PIN, UART_RX_PIN,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

/* Modem power pulse */
static void modem_power_on(void)
{
gpio_set_direction(MODEM_PWRKEY, GPIO_MODE_OUTPUT);
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(MODEM_PWRKEY, 0);
vTaskDelay(pdMS_TO_TICKS(1200));
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(6000));
}

/* AT helpers */
static void at_cmd(const char *cmd, int delay_ms)
{
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}

static void at_cmd_log(const char *cmd, int collect_ms)
{
uint8_t buf[256];
uart_flush_input(MODEM_UART);
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(collect_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “%s rsp: %s”, cmd, buf);
}
}
}

/* Wait for CONNECT /
static bool wait_for_connect(int timeout_ms)
{
uint8_t buf[256];
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “MODEM: %s”, buf);
if (strstr((char
)buf, “CONNECT”)) return true;
if (strstr((char*)buf, “ERROR”) || strstr((char*)buf, “NO CARRIER”)) return false;
}
}
ESP_LOGE(TAG, “Timed out waiting for CONNECT”);
return false;
}

/* PPP callbacks */
static u32_t ppp_output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
{
uart_write_bytes(MODEM_UART, (const char *)data, len);
return len;
}

static void ppp_status_cb(ppp_pcb *pcb, int err, void *ctx)
{
if (err == PPPERR_NONE) ESP_LOGI(TAG, “PPP CONNECTED”);
else ESP_LOGE(TAG, “PPP ERROR: %d”, err);
}

/* PPP RX task */
static void ppp_rx_task(void *arg)
{
uint8_t buf[512];
while (1) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf), portMAX_DELAY);
if (len > 0 && ppp) {
pppos_input_tcpip(ppp, buf, len);
}
}
}

/* IP events /
static void ip_event_handler(void
arg, esp_event_base_t base, int32_t id, void* data)
{
if (id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv4: " IPSTR, IP2STR(&ev->ip_info.ip));
} else if (id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *ev6 = (ip_event_got_ip6_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv6: " IPV6STR, IPV62STR(ev6->ip6_info.ip));
}
}

/* PDP bring-up on CID1, IPV6, activate before dial */
static bool setup_pdp_and_connect(void)
{
ESP_LOGI(TAG, “Setting PDP CID1 as IPV6 and activating”);

at_cmd("AT+QIDEACT=1", 500);  // deactivate lingering session
char cmd[96];
snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"%s\",\"%s\"", MODEM_PDP_TYPE, APN); // IPV6, jionet
at_cmd(cmd, 500);
at_cmd("AT+CGACT=1,1", 800);  // activate CID1
at_cmd_log("AT+CGACT?", 500); // expect: +CGACT: 1,1
at_cmd_log("AT+CGPADDR=1", 500); // should show a global IPv6

uart_flush_input(MODEM_UART);
ESP_LOGI(TAG, "Dialing ATD*99***1# ...");
uart_write_bytes(MODEM_UART, "ATD*99***1#\r", 12);
bool got_connect = wait_for_connect(10000);

if (!got_connect) {
    ESP_LOGW(TAG, "Dial failed; trying AT+CGDATA on CID1");
    uart_flush_input(MODEM_UART);
    uart_write_bytes(MODEM_UART, "AT+CGDATA=\"PPP\",1\r", 18);
    got_connect = wait_for_connect(10000);
}
return got_connect;

}

/* Start PPP */
static void start_pppos(void)
{
at_cmd_log(“AT+CPIN?”, 400);
at_cmd_log(“AT+CSQ”, 400);
at_cmd_log(“AT+CGATT?”, 400);

bool connected = setup_pdp_and_connect();
if (!connected) {
    ESP_LOGE(TAG, "No CONNECT; aborting PPP start");
    return;
}

esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP();
esp_netif_ppp = esp_netif_new(&cfg);
assert(esp_netif_ppp);
esp_netif_attach(esp_netif_ppp, &ppp_netif);

ppp = pppapi_pppos_create(&ppp_netif, ppp_output_cb, ppp_status_cb, NULL);
if (!ppp) { ESP_LOGE(TAG, "pppos_create failed"); return; }

pppapi_set_default(ppp);
ppp_set_usepeerdns(ppp, 1);
pppapi_set_auth(ppp, PPPAUTHTYPE_NONE, NULL, NULL);

xTaskCreatePinnedToCore(ppp_rx_task, "ppp_rx", 6144, NULL, 6, NULL, 1);

ESP_LOGI(TAG, "Calling pppapi_connect...");
pppapi_connect(ppp, 0);

// If the peer does not provide DNS over IPv6, set manually:
// esp_netif_dns_info_t dns = {
//     .ip = {
//         .type = IPADDR_TYPE_V6,
//         .u_addr.ip6 = { PP_HTONL(0x20014860), PP_HTONL(0x48600000), 0, PP_HTONL(0x00008888) } // 2001:4860:4860::8888
//     }
// };
// esp_netif_set_dns_info(esp_netif_ppp, ESP_NETIF_DNS_MAIN, &dns);

}

/* MAIN */
void app_main(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL));

uart_init();
modem_power_on();
start_pppos();

for (;;) {
    vTaskDelay(pdMS_TO_TICKS(5000));
}

}

OUTPUT LOG

pppos_client_main.c (6.7 KB)


Looking Forward for your responce.
Thank you.

Hi Vignesh,

Thanks for the update and for sharing the new logs and code.

What your latest logs confirm is that the:

  1. IPv6 PDP is working correctly at the modem side

+CGPADDR: 1,“2405:203:5880:152::10”

This confirms:

-Jio APN jionet is active
-A global IPv6 address is successfully assigned by the network
-Modem firmware and SIM behavior are OK

  1. Dial command is correct and data mode is entered

ATD99**1#
CONNECT

This means:

-The modem has switched to PPP data mode
-UART is now carrying raw PPP frames (no more AT responses)

  1. PPPoS does not proceed after pppapi_connect()

Calling pppapi_connect…

No IPCP/IPV6CP completion or IP events follow.

This is the key symptom.

Root cause (important):

-This is not a modem firmware issue.

The limitation is on the ESP-IDF v4.4 + lwIP PPP stack, specifically:

-ESP-IDF v4.4 PPPoS does not fully support IPv6-only PPP sessions
-Only link-local IPv6 (fe80::). is reliably handled
-Global IPv6 routing and DNS over PPP are incomplete
-When the network is IPv6-only (like Jio), PPP negotiation stalls after CONNECT

This matches exactly what you are seeing.

Even when AT+CGPADDR shows a valid global IPv6, lwIP v4.4 cannot use it for traffic.

After CONNECT, PPP still requires:

-Successful IPv6CP negotiation
-Proper netif IPv6 bring-up
-DNS handling over IPv6

In ESP-IDF v4.4:

-pppos_input_tcpip() + pppapi_connect() works reliably for IPv4
-IPv6-only PPP is partially implemented and unstable

So the behavior you see is expected with this IDF version.

Recommended solutions

Option 1 (Strongly recommended): Upgrade ESP-IDF

-Move to ESP-IDF v5.1 or later
-PPP IPv6 support is significantly improved
-Multiple users have successfully connected IPv6-only cellular networks (including Jio) using PPPoS in v5.x
-This is the correct long-term fix.

Option 2: Force IPv4 (not suitable for Jio)

-Not applicable here since Jio APN is IPv6-only
-IPv4 fallback will not work reliably

Option 3: Use USB (QMI / ECM) instead of PPP

-If your hardware allows USB:
-EC200U works much better with ECM/QMI
-Native IPv6 routing and DNS
-No PPP limitations
-Recommended for IPv6-only operators

About firmware

At this point:

-There is no firmware change required on EC200U
-Your modem behavior is correct and standards-compliant
-Issue is entirely on the host TCP/IP stack side

Hope this helps!

Have a great day!

Best Regards,
Ananthan

Dear Ananthan , Thank you for your valuable suggestions.
I upgraded the esp-idf Version tp 5.1.6 LTS , and tried the same firmware by changing few api’s comapatible to the newer version , but still the negociation is stalling , and this time the problem is with setting up the auth, but responce is nill and the lcp is stalling.
I tried setting it to null , forcing the chap only , pap only and also set to default to any auth .
ppp_set_auth(ppp, PPPAUTHTYPE_PAP, “user”, “pass”);
ppp_set_auth(ppp, PPPAUTHTYPE_CHAP, “user”, “pass”);
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, “user”, “pass”);

But either of them worked , Kindly look into it and Please tell me how to fix this and get an ipv6 ip over ppp,
and the network is crashing.
Below attaching the updated firmwar and the output logs.
kindly consider.

#include <string.h>
#include <stdio.h>

#include “freertos/FreeRTOS.h”
#include “freertos/task.h”

#include “driver/uart.h”
#include “driver/gpio.h”

#include “netif/ppp/pppapi.h”
#include “netif/ppp/pppos.h”
#include “netif/ppp/ppp.h”
#include “lwip/netif.h”
#include “lwip/sockets.h”
#include “lwip/inet.h”

#include “esp_log.h”
#include “esp_event.h”
#include “esp_netif.h”

#define MODEM_UART UART_NUM_1
#define UART_TX_PIN 37 // adjust to your wiring
#define UART_RX_PIN 36 // adjust to your wiring
#define UART_BAUDRATE 115200
#define MODEM_PWRKEY 1 // adjust if your PWRKEY is another GPIO
#define APN “jionet”
#define MODEM_PDP_TYPE “IPV6” // IPv6-only for Jio

static const char *TAG = “PPPOS_ONLY”;
static ppp_pcb *ppp;
static struct netif ppp_netif;
static esp_netif_t *esp_netif_ppp;

/* UART init */
static void uart_init(void)
{
uart_config_t cfg = {
.baud_rate = UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_driver_install(MODEM_UART, 4096, 4096, 0, NULL, 0);
uart_param_config(MODEM_UART, &cfg);
uart_set_pin(MODEM_UART, UART_TX_PIN, UART_RX_PIN,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

/* Modem power pulse */
static void modem_power_on(void)
{
gpio_set_direction(MODEM_PWRKEY, GPIO_MODE_OUTPUT);
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(MODEM_PWRKEY, 0);
vTaskDelay(pdMS_TO_TICKS(1200));
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(6000));
}

/* AT helpers */
static void at_cmd(const char *cmd, int delay_ms)
{
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}

static void at_cmd_log(const char *cmd, int collect_ms)
{
uint8_t buf[256];
uart_flush_input(MODEM_UART);
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(collect_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “%s rsp: %s”, cmd, buf);
}
}
}

/* Wait for CONNECT /
static bool wait_for_connect(int timeout_ms)
{
uint8_t buf[256];
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “MODEM: %s”, buf);
if (strstr((char
)buf, “CONNECT”)) return true;
if (strstr((char*)buf, “ERROR”) || strstr((char*)buf, “NO CARRIER”)) return false;
}
}
ESP_LOGE(TAG, “Timed out waiting for CONNECT”);
return false;
}

/* PPP callbacks */
static u32_t ppp_output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
{
uart_write_bytes(MODEM_UART, (const char *)data, len);
return len;
}

static void ppp_status_cb(ppp_pcb *pcb, int err, void *ctx)
{
if (err == PPPERR_NONE) ESP_LOGI(TAG, “PPP CONNECTED”);
else ESP_LOGE(TAG, “PPP ERROR: %d”, err);
}

/* PPP RX task */
static void ppp_rx_task(void *arg)
{
uint8_t buf[512];
while (1) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf), portMAX_DELAY);
if (len > 0 && ppp) {
pppos_input_tcpip(ppp, buf, len);
}
}
}

/* IP events /
static void ip_event_handler(void
arg, esp_event_base_t base, int32_t id, void* data)
{
if (id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv4: " IPSTR, IP2STR(&ev->ip_info.ip));
} else if (id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *ev6 = (ip_event_got_ip6_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv6: " IPV6STR, IPV62STR(ev6->ip6_info.ip));
}
}

/* PDP bring-up on CID1, IPV6, activate before dial */
static bool setup_pdp_and_connect(void)
{
ESP_LOGI(TAG, “Setting PDP CID1 as IPV6 and activating”);

at_cmd("AT+QIDEACT=1", 500);  // deactivate lingering session
char cmd[96];
snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"%s\",\"%s\"", MODEM_PDP_TYPE, APN); // IPV6, jionet
at_cmd(cmd, 500);
at_cmd("AT+CGACT=1,1", 800);  // activate CID1
at_cmd_log("AT+CGACT?", 500); // expect: +CGACT: 1,1
at_cmd_log("AT+CGPADDR=1", 500); // should show a global IPv6

uart_flush_input(MODEM_UART);
ESP_LOGI(TAG, "Dialing ATD*99***1# ...");
uart_write_bytes(MODEM_UART, "ATD*99***1#\r", 12);
bool got_connect = wait_for_connect(10000);

if (!got_connect) {
    ESP_LOGW(TAG, "Dial failed; trying AT+CGDATA on CID1");
    uart_flush_input(MODEM_UART);
    uart_write_bytes(MODEM_UART, "AT+CGDATA=\"PPP\",1\r", 18);
    got_connect = wait_for_connect(10000);
}
return got_connect;

}

/* Start PPP */
static void start_pppos(void)
{
at_cmd_log(“AT+CPIN?”, 400);
at_cmd_log(“AT+CSQ”, 400);
at_cmd_log(“AT+CGATT?”, 400);

bool connected = setup_pdp_and_connect();
if (!connected) {
    ESP_LOGE(TAG, "No CONNECT; aborting PPP start");
    return;
}

esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP();
esp_netif_ppp = esp_netif_new(&cfg);
assert(esp_netif_ppp);
esp_netif_attach(esp_netif_ppp, &ppp_netif);

ppp = pppapi_pppos_create(&ppp_netif, ppp_output_cb, ppp_status_cb, NULL);
if (!ppp) { ESP_LOGE(TAG, "pppos_create failed"); return; }

pppapi_set_default(ppp);
ppp_set_usepeerdns(ppp, 1);
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "user", "pass");

xTaskCreatePinnedToCore(ppp_rx_task, "ppp_rx", 6144, NULL, 6, NULL, 1);

ESP_LOGI(TAG, "Calling pppapi_connect...");
pppapi_connect(ppp, 0);

// If the peer does not provide DNS over IPv6, set manually:
// esp_netif_dns_info_t dns = {
//     .ip = {
//         .type = IPADDR_TYPE_V6,
//         .u_addr.ip6 = { PP_HTONL(0x20014860), PP_HTONL(0x48600000), 0, PP_HTONL(0x00008888) } // 2001:4860:4860::8888
//     }
// };
// esp_netif_set_dns_info(esp_netif_ppp, ESP_NETIF_DNS_MAIN, &dns);

}

/* MAIN */
void app_main(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL));

uart_init();
modem_power_on();
start_pppos();

for (;;) {
    vTaskDelay(pdMS_TO_TICKS(5000));
}

}

entry 0x403c9908
I (27) boot: ESP-IDF HEAD-HASH-NOTFOUND 2nd stage bootloader
I (27) boot: compile time Dec 19 2025 12:37:10
I (27) boot: Multicore bootloader
I (31) boot: chip revision: v0.2
I (35) boot.esp32s3: Boot SPI Speed : 80MHz
I (40) boot.esp32s3: SPI Mode : DIO
I (44) boot.esp32s3: SPI Flash Size : 16MB
I (49) boot: Enabling RNG early entropy source…
I (55) boot: Partition Table:
I (58) boot: ## Label Usage Type ST Offset Length
I (65) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (73) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (80) boot: 2 factory factory app 00 00 00010000 00100000
I (88) boot: End of partition table
I (92) esp_image: segment 0: paddr=00010020 vaddr=3c040020 size=13d60h ( 81248) map
I (115) esp_image: segment 1: paddr=00023d88 vaddr=3fc92400 size=02734h ( 10036) load
I (117) esp_image: segment 2: paddr=000264c4 vaddr=40374000 size=09b54h ( 39764) load
I (130) esp_image: segment 3: paddr=00030020 vaddr=42000020 size=3d02ch (249900) map
I (175) esp_image: segment 4: paddr=0006d054 vaddr=4037db54 size=04800h ( 18432) load
I (185) boot: Loaded app from partition at offset 0x10000
I (185) boot: Disabling RNG early entropy source…
I (197) cpu_start: Multicore app
I (197) cpu_start: Pro cpu up.
I (197) cpu_start: Starting app cpu, entry point is 0x40375380
— 0x40375380: call_start_cpu1 at C:/Espressif/frameworks/esp-idf-v5.1.6/components/esp_system/port/cpu_start.c:160

I (0) cpu_start: App cpu up.
I (215) cpu_start: Pro cpu start user code
I (215) cpu_start: cpu freq: 160000000 Hz
I (215) cpu_start: Application information:
I (218) cpu_start: Project name: pppos_jio
I (223) cpu_start: App version: 1
I (228) cpu_start: Compile time: Dec 19 2025 12:36:37
I (234) cpu_start: ELF file SHA256: 95fb326dc14145bb…
I (240) cpu_start: ESP-IDF: HEAD-HASH-NOTFOUND
I (246) cpu_start: Min chip rev: v0.0
I (250) cpu_start: Max chip rev: v0.99
I (255) cpu_start: Chip rev: v0.2
I (260) heap_init: Initializing. RAM available for dynamic allocation:
I (267) heap_init: At 3FC95F18 len 000537F8 (333 KiB): DRAM
I (273) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (280) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (286) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (294) spi_flash: detected chip: generic
I (297) spi_flash: flash io: dio
I (301) sleep: Configure to isolate all GPIO pins in sleep state
I (308) sleep: Enable automatic switching of GPIO sleep configuration
I (315) app_start: Starting scheduler on CPU0
I (320) app_start: Starting scheduler on CPU1
I (320) main_task: Started on CPU0
I (330) main_task: Calling app_main()
netif: netmask of interface set to 255.0.0.0
netif: GW address of interface set to 127.0.0.1
netif_set_ipaddr: netif address being changed
netif: added interface lo IP addr 127.0.0.1 netmask 255.0.0.0 gw 127.0.0.1
ip6_output_if: lo0
IPv6 header:
±------------------------------+
| 6 | 0 | 0 | (ver, class, flow)
±------------------------------+
| 16 | 58 | 255 | (plen, nexth, hopl)
±------------------------------+
| 0 | 0 | 0 | 0 | (src)
| 0 | 0 | 0 | 1 |
±------------------------------+
| ff02 | 0 | 0 | 0 | (dest)
| 0 | 0 | 0 | 2 |
±------------------------------+
netif->output_ip6()
ip6_input: packet not for us.
ip6_output_if: lo0
IPv6 header:
±------------------------------+
| 6 | 0 | 0 | (ver, class, flow)
±------------------------------+
| 16 | 58 | 255 | (plen, nexth, hopl)
±------------------------------+
| 0 | 0 | 0 | 0 | (src)
| 0 | 0 | 0 | 1 |
±------------------------------+
| ff02 | 0 | 0 | 0 | (dest)
| 0 | 0 | 0 | 2 |
±------------------------------+
netif->output_ip6()
ip6_input: packet not for us.
I (7860) PPPOS_ONLY: AT+CPIN? rsp:
+CPIN: READY

OK

I (8270) PPPOS_ONLY: AT+CSQ rsp:
+CSQ: 21,99

OK

I (8680) PPPOS_ONLY: AT+CGATT? rsp:
+CGATT: 1

OK

I (8880) PPPOS_ONLY: Setting PDP CID1 as IPV6 and activating
ip6_output_if: lo0
IPv6 header:
±------------------------------+
| 6 | 0 | 0 | (ver, class, flow)
±------------------------------+
| 16 | 58 | 255 | (plen, nexth, hopl)
±------------------------------+
| 0 | 0 | 0 | 0 | (src)
| 0 | 0 | 0 | 1 |
±------------------------------+
| ff02 | 0 | 0 | 0 | (dest)
| 0 | 0 | 0 | 2 |
±------------------------------+
netif->output_ip6()
ip6_input: packet not for us.
I (10890) PPPOS_ONLY: AT+CGACT? rsp:
+CGACT: 1,1
+CGACT: 2,0

OK

I (11500) PPPOS_ONLY: AT+CGPADDR=1 rsp:
+CGPADDR: 1,“2405:203:5880:152::10”

OK

I (11900) PPPOS_ONLY: Dialing ATD99**1# …
I (12110) PPPOS_ONLY: MODEM:
CONNECT

netif: netmask of interface set to 255.255.255.255
netif: added interface pp IP addr 0.0.0.0 netmask 255.255.255.255 gw 0.0.0.0
ppp phase changed[1]: phase=0
netif: netmask of interface set to 255.255.255.255
netif: added interface pp IP addr 0.0.0.0 netmask 255.255.255.255 gw 0.0.0.0
ppp phase changed[2]: phase=0
netif: setting default interface pp
I (12130) PPPOS_ONLY: Calling pppapi_connect…
ppp_connect[2]: holdoff=0
ppp phase changed[2]: phase=3
pppos_connect: unit 2: connecting
ppp_start[2]
ppp phase changed[2]: phase=6
pppos_send_config[2]: out_accm=FF FF FF FF
ppp_send_config[2]
pppos_recv_config[2]: in_accm=FF FF FF FF
ppp_recv_config[2]
ppp: auth protocols: PAP=1 CHAP=1 CHAP_MD5=1
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
pppos_write[2]: len=24
ppp_start[2]: finished
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
pppos_write[2]: len=24
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
pppos_write[2]: len=24
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
pppos_write[2]: len=24
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
pppos_write[2]: len=24
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
pppos_write[2]: len=24
pppos_input[2]: got 512 bytes
rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
sent [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
pppos_write[2]: len=29
rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
netif_set_mtu[2]: mtu=1500
pppos_send_config[2]: out_accm=0 0 0 0
ppp_send_config[2]
pppos_recv_config[2]: in_accm=0 0 0 0
ppp_recv_config[2]
ppp phase changed[2]: phase=7
rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
ppp phase changed[2]: phase=6
pppos_send_config[2]: out_accm=FF FF FF FF
ppp_send_config[2]
pppos_recv_config[2]: in_accm=0 0 0 0
ppp_recv_config[2]
ppp: auth protocols: PAP=1 CHAP=1 CHAP_MD5=1
sent [LCP ConfReq id=0x2 <asyncmap 0x0> <magic 0x63ed6bf6> ]
pppos_write[2]: len=24
sent [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
pppos_write[2]: len=29
rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
sent [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
pppos_write[2]: len=29
rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0x6d05204b> ]
rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
sent [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0xab02e37e> ]
pppos_write[2]: len=29

pppos_client_main.c (6.8 KB)

Looking forward for your responce .
Thanks and regards.
Mail id - vigneshvishalansai@gmail.com

Hi Vignesh,

Thank you for the update and for testing with ESP-IDF v5.1.6 LTS. I’ve carefully reviewed the new logs and behavior.

I see Modem and network side are working correctly.

+CGPADDR: 1,“2405:203:5880:152::10”

-Jio APN jionet is active
-A global IPv6 address is successfully assigned

This confirms there is no firmware or SIM issue on the EC200U side

PPP data mode is entered correctly

ATD99**1#
CONNECT

-The modem is in PPP data mode
-UART is carrying raw PPP frames as expected
-LCP negotiation starts and partially completes

sent [LCP ConfReq]
rcvd [LCP ConfReq]
sent [LCP ConfAck]
rcvd [LCP ConfAck]

This confirms PPP framing, UART RX/TX, and timing are all correct

but PPP repeatedly falls back to LCP and never progresses
-LCP keeps renegotiating
-Authentication is advertised but never completes
-PPP never transitions to IPV6CP / network phase

This is the critical symptom. This behavior is not caused by authentication settings and not caused by modem firmware.

On cellular networks like Jio:

-PPP authentication is typically ignored or auto-accepted
-Username/password values are not validated
-For IPv6-only PDPs, no real PAP/CHAP exchange is required

Your logs confirm this:

-The network does not request credentials
-LCP keeps restarting even when auth is set to NONE / PAP / CHAP / ANY

So, this is not an auth mismatch issue.

Actual reason PPP stalls (confirmed)

Even in ESP-IDF v5.1, lwIP PPP has the following limitation:

IPv6-only PPP sessions on cellular networks are not fully supported in lwIP PPPoS

What happens internally is:

-LCP negotiates correctly
-Authentication phase is nominal
-IPv6CP does not fully complete
-Global IPv6 from the modem is not bound correctly to the PPP netif
-lwIP keeps restarting LCP → negotiation loop

This exact pattern (LCP loop without IPV6CP completion) is a known PPPoS limitation, not a user configuration error.

PPPoS still relies on lwIP to negotiate IPv6CP, and this is where it stalls.

Best Regards,
Ananthan

Dear Ananthan , Thanks for the clarifications.

Tried all the esp-idf versions but still fails since the IPV6CP limitation on the lwip ppp, earlier i have also tired adding an dependency esp_modem and tried using the bg96 drivers which matches the quectel ec200u-cn, but there was a compatibility issue and failed to bring up the ipv6 ppp , later swiched to the raw lwip pppos , but could’t make it since because of the internal limitations.

Now what are the other chances or method to successfully establish ipv6 IP internet via pppos using libraries with Jio APN and ping any website to ensure the successfull internet reach on EC200u-cn .

Looking forward for the solution .
Thanks and Regards.

Dear Vignesh,

Thanks for the detailed testing and confirmation.

At this point, there is no reliable way to establish IPv6 internet over PPPoS on ESP32 using lwIP libraries with Jio’s IPv6-only APN. This is due to internal limitations of lwIP PPP (IPv6CP) and not because of the EC200U firmware, AT commands, or your implementation.

You have already tried all valid options (different ESP-IDF versions, esp_modem, raw PPPoS), and they all hit the same limitation.

For Jio IPv6-only networks, PPPoS is unfortunately not supported on ESP32.
The recommended and working solution is to use USB ECM / QMI mode, which provides native IPv6 support and stable internet connectivity.

I will further dig deeper into this and advise if there are any new findings or alternatives.

Have a great day!

Regards,
Ananthan

Hi Ananthan,
As per the above context , fail to establish ipv6 internet via raw lwip ppp using an ipv6 jiosim , due its internal limitations.
I desided to change the APN (sim) to vi which also supports dual stack as well as ipv4 and ipv6 forced.
and tried on both the versions esp-idf -5.1,5.5.
still seem the same issue , as on the 5.1 version earlier the log states that the chap md5 response was failed so the lcp could notnegotiate with esp32 and the ppp could’nt established (jio ipv6) ,
morever the ppp frames on the lwip debug was seen, but failed to negotiate the ipv6cp and the auth response.
Where then i switched to the vi (www)apn and forced the ipv4, which succesfully got the global ip but failed to negotiate the same on the MCU side.
Im pretty sure its a firmware bug and please let me know why the ppp is failing , though on the ipv4 which is not an internal limitation which we found on the jio ipv6.
Kindly unterstand the importance of this and help me ananthan.
Kindly find the firmware and output logs.

#include <string.h>
#include <stdio.h>

#include “freertos/FreeRTOS.h”
#include “freertos/task.h”

#include “driver/uart.h”
#include “driver/gpio.h”

#include “netif/ppp/pppapi.h”
#include “netif/ppp/pppos.h”
#include “netif/ppp/ppp.h”
#include “lwip/netif.h”
#include “lwip/sockets.h”
#include “lwip/inet.h”

#include “esp_log.h”
#include “esp_event.h”
#include “esp_netif.h”

#define MODEM_UART UART_NUM_1
#define UART_TX_PIN 37 // adjust to your wiring
#define UART_RX_PIN 36 // adjust to your wiring
#define UART_BAUDRATE 115200
#define MODEM_PWRKEY 1 // adjust if your PWRKEY is another GPIO
#define APN “WWW”
#define MODEM_PDP_TYPE “IP” // IPv6-only for Jio

static const char *TAG = “PPPOS_ONLY”;
static ppp_pcb *ppp;
static struct netif ppp_netif;
static esp_netif_t *esp_netif_ppp;

/* UART init */
static void uart_init(void)
{
uart_config_t cfg = {
.baud_rate = UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_driver_install(MODEM_UART, 4096, 4096, 0, NULL, 0);
uart_param_config(MODEM_UART, &cfg);
uart_set_pin(MODEM_UART, UART_TX_PIN, UART_RX_PIN,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

/* Modem power pulse */
static void modem_power_on(void)
{
gpio_set_direction(MODEM_PWRKEY, GPIO_MODE_OUTPUT);
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(MODEM_PWRKEY, 0);
vTaskDelay(pdMS_TO_TICKS(1200));
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(6000));
}

/* AT helpers */
static void at_cmd(const char *cmd, int delay_ms)
{
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}

static void at_cmd_log(const char *cmd, int collect_ms)
{
uint8_t buf[256];
uart_flush_input(MODEM_UART);
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(collect_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “%s rsp: %s”, cmd, buf);
}
}
}

/* Wait for CONNECT /
static bool wait_for_connect(int timeout_ms)
{
uint8_t buf[256];
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “MODEM: %s”, buf);
if (strstr((char
)buf, “CONNECT”)) return true;
if (strstr((char*)buf, “ERROR”) || strstr((char*)buf, “NO CARRIER”)) return false;
}
}
ESP_LOGE(TAG, “Timed out waiting for CONNECT”);
return false;
}

/* PPP callbacks */
static u32_t ppp_output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
{
uart_write_bytes(MODEM_UART, (const char *)data, len);
return len;
}

static void ppp_status_cb(ppp_pcb *pcb, int err, void *ctx)
{
if (err == PPPERR_NONE) ESP_LOGI(TAG, “PPP CONNECTED”);
else ESP_LOGE(TAG, “PPP ERROR: %d”, err);
}

/* PPP RX task */
static void ppp_rx_task(void *arg)
{
uint8_t buf[512];
while (1) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf), portMAX_DELAY);
if (len > 0 && ppp) {
pppos_input_tcpip(ppp, buf, len);
}
}
}

/* IP events /
static void ip_event_handler(void
arg, esp_event_base_t base, int32_t id, void* data)
{
if (id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv4: " IPSTR, IP2STR(&ev->ip_info.ip));
} else if (id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *ev6 = (ip_event_got_ip6_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv6: " IPV6STR, IPV62STR(ev6->ip6_info.ip));
}
}

/* PDP bring-up on CID1, IPV6, activate before dial */
static bool setup_pdp_and_connect(void)
{
ESP_LOGI(TAG, “Setting PDP CID1 as IPV6 and activating”);

at_cmd("AT+QIDEACT=1", 500);  // deactivate lingering session
char cmd[96];
snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"%s\",\"%s\"", MODEM_PDP_TYPE, APN); // IPV6, jionet
at_cmd(cmd, 500);
at_cmd("AT+CGACT=1,1", 800);  // activate CID1
at_cmd_log("AT+CGACT?", 500); // expect: +CGACT: 1,1
at_cmd_log("AT+CGPADDR=1", 500); // should show a global IPv6

uart_flush_input(MODEM_UART);
ESP_LOGI(TAG, "Dialing ATD*99# ...");
uart_write_bytes(MODEM_UART, "ATD*99#\r", 8);
bool got_connect = wait_for_connect(10000);

if (!got_connect) {
    ESP_LOGW(TAG, "Dial failed; trying AT+CGDATA on CID1");
    uart_flush_input(MODEM_UART);
    uart_write_bytes(MODEM_UART, "AT+CGDATA=\"PPP\",1\r", 18);
    got_connect = wait_for_connect(10000);
}
return got_connect;

}

/* Start PPP */
static void start_pppos(void)
{
at_cmd_log(“AT+CPIN?”, 1000);
at_cmd_log(“AT+CSQ”, 1000);
at_cmd_log(“AT+CGATT?”, 1000);

bool connected = setup_pdp_and_connect();
if (!connected) {
    ESP_LOGE(TAG, "No CONNECT; aborting PPP start");
    return;
}

esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP();
esp_netif_ppp = esp_netif_new(&cfg);
assert(esp_netif_ppp);
esp_netif_attach(esp_netif_ppp, &ppp_netif);

ppp = pppapi_pppos_create(&ppp_netif, ppp_output_cb, ppp_status_cb, NULL);
if (!ppp) { ESP_LOGE(TAG, "pppos_create failed"); return; }

pppapi_set_default(ppp);
ppp_set_usepeerdns(ppp, 1);
ppp_set_auth(ppp, PPPAUTHTYPE_CHAP, "user", "pass");

xTaskCreatePinnedToCore(ppp_rx_task, "ppp_rx", 6144, NULL, 6, NULL, 1);

ESP_LOGI(TAG, "Calling pppapi_connect...");
pppapi_connect(ppp, 0);

// If the peer does not provide DNS over IPv6, set manually:
// esp_netif_dns_info_t dns = {
//     .ip = {
//         .type = IPADDR_TYPE_V6,
//         .u_addr.ip6 = { PP_HTONL(0x20014860), PP_HTONL(0x48600000), 0, PP_HTONL(0x00008888) } // 2001:4860:4860::8888
//     }
// };
// esp_netif_set_dns_info(esp_netif_ppp, ESP_NETIF_DNS_MAIN, &dns);

}

/* MAIN */
void app_main(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL));

uart_init();
modem_power_on();
start_pppos();

for (;;) {
    vTaskDelay(pdMS_TO_TICKS(5000));
}

}

pppos_client_main.c (6.8 KB)

Looking forward for your responce .
Thanks and regards

Hi Vignesh,

Thanks for sharing the latest logs and code.

From the log, the modem side is working correctly. I see that the SIM is ready, network attached, PDP context is activated, a valid IPv4 address is assigned (CGPADDR), dial command returns CONNECT, so the modem is in PPP data mode.This confirms there is no modem firmware or APN issue.

The failure happens after CONNECT, during PPP negotiation on the ESP32 (lwIP side). PPP frames are exchanged, but the negotiation does not complete.

Based on your code and logs, there are three likely causes on the MCU side:

-Authentication mismatch
-Your code forces CHAP with dummy credentials (“user” / “pass”).

Indian operators (Jio / VI) usually require no authentication or allow the network to decide. Forcing CHAP can cause PPP to stall during LCP/Auth.

Please try using ppp_set_auth(ppp, PPPAUTHTYPE_ANY, “”, “”);

You manually activate PDP using AT+CGACT and fetch IP before dialing. In some networks, this can conflict with PPP, as the IP is already bound internally. PPP prefers the PDP context to be finalized during ATD*99#. lwIP PPP is sensitive to authentication timing and IPCP handling.

For internal checking, can you help to share the module firmware information? You can issue AT+QGMR command or share the IMEI of the module so that I can check internally.

Thanks!
Have a great day!

Best Regards,
Ananthan

Hi Ananthan, Thanks for the update .
As of now , Modem side is OK (control plane) :-
+CPIN: READY
+CSQ: 19,99
+CGATT: 1
+CGACT: 1,1
+CGPADDR: 1,“10.25.124.241”
And successfully enter PPP data mode :-
Dialing AT+CGDATA=“PPP”,1 … // tried ATD*99# dialing as well.
MODEM:
CONNECT.

ESP starts PPP correctly
pppapi_connect…
pppos_connect: unit 2: connecting
ppp_start

LCP negotiation starts :-
sent [LCP ConfReq id=0x1 …]
sent [LCP ConfReq]
sent [LCP ConfReq]
sent [LCP ConfReq]

And the problem is Modem NEVER responds to the LCP ,
(no LCP ConfAck ever received)
LCP: timeout sending Config-Requests
PPP ERROR: 6
Connection terminated.

The module firmware information : -

ATE0

OK

AT+QCFG=“dataformat”,0,0

+CME ERROR: 3

AT+IFC=0,0

OK

AT+IPR=115200

OK

AT&W

OK

EC200UCNAAR03A03M08

OK

Why the modems not responding to the lcp, where the esp side is working fine, also checked with the wiring
RX36 / TX37 , but the modem fails to respond to the lcp.

Attaching the latest firmware and the output logs, kindly consider.

#include <string.h>
#include <stdio.h>

#include “freertos/FreeRTOS.h”
#include “freertos/task.h”

#include “driver/uart.h”
#include “driver/gpio.h”

#include “netif/ppp/pppapi.h”
#include “netif/ppp/pppos.h”
#include “netif/ppp/ppp.h”
#include “lwip/netif.h”
#include “lwip/sockets.h”
#include “lwip/inet.h”

#include “esp_log.h”
#include “esp_event.h”
#include “esp_netif.h”

// Set to 1 if you wire RTS/CTS and set modem IFC=2,2; otherwise keep 0 (TX/RX only).
#define USE_HW_FLOWCTRL 0

#define MODEM_UART UART_NUM_1
#define UART_TX_PIN 37 // adjust to your wiring
#define UART_RX_PIN 36 // adjust to your wiring
#define UART_BAUDRATE 115200
#define MODEM_PWRKEY 1 // adjust if your PWRKEY is another GPIO
#define APN “www” // Vi India APN is “www”; change if needed
#define MODEM_PDP_TYPE “IP” // use “IP” or “IPV4V6” if needed

static const char *TAG = “PPPOS_ONLY”;
static ppp_pcb *ppp;
static struct netif ppp_netif;
static esp_netif_t *esp_netif_ppp;

/* UART init */
static void uart_init(void)
{
uart_config_t cfg = {
.baud_rate = UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
#if USE_HW_FLOWCTRL
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.rx_flow_ctrl_thresh = 64,
#else
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
#endif
};
uart_driver_install(MODEM_UART, 4096, 4096, 0, NULL, 0);
uart_param_config(MODEM_UART, &cfg);
uart_set_pin(MODEM_UART, UART_TX_PIN, UART_RX_PIN,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#if USE_HW_FLOWCTRL
uart_set_hw_flow_ctrl(MODEM_UART, UART_HW_FLOWCTRL_CTS_RTS, 64);
#endif
}

/* Modem power pulse */
static void modem_power_on(void)
{
gpio_set_direction(MODEM_PWRKEY, GPIO_MODE_OUTPUT);
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(MODEM_PWRKEY, 0);
vTaskDelay(pdMS_TO_TICKS(1200));
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(6000));
}

/* AT helpers */
static void at_cmd(const char *cmd, int delay_ms)
{
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}

static void at_cmd_log(const char *cmd, int collect_ms)
{
uint8_t buf[256];
uart_flush_input(MODEM_UART);
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(collect_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “%s rsp: %s”, cmd, buf);
}
}
}

/* Wait for CONNECT /
static bool wait_for_connect(int timeout_ms)
{
uint8_t buf[256];
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “MODEM: %s”, buf);
if (strstr((char
)buf, “CONNECT”)) return true;
if (strstr((char*)buf, “ERROR”) || strstr((char*)buf, “NO CARRIER”)) return false;
}
}
ESP_LOGE(TAG, “Timed out waiting for CONNECT”);
return false;
}

/* Wait for +CGATT: 1 /
static bool wait_for_attach(int max_checks, int interval_ms)
{
for (int i = 0; i < max_checks; ++i) {
uint8_t buf[128];
uart_flush_input(MODEM_UART);
uart_write_bytes(MODEM_UART, “AT+CGATT?\r”, 10);
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, interval_ms / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “AT+CGATT? rsp: %s”, buf);
if (strstr((char
)buf, “+CGATT: 1”)) {
return true;
}
}
}
return false;
}

/* PPP callbacks */
static u32_t ppp_output_cb(ppp_pcb *pcb, const void *data, u32_t len, void *ctx)
{
uart_write_bytes(MODEM_UART, (const char *)data, len);
return len;
}

static void ppp_status_cb(ppp_pcb *pcb, int err, void *ctx)
{
if (err == PPPERR_NONE) ESP_LOGI(TAG, “PPP CONNECTED”);
else ESP_LOGE(TAG, “PPP ERROR: %d”, err);
}

/* PPP RX task */
static void ppp_rx_task(void *arg)
{
uint8_t buf[1520];
while (1) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf), portMAX_DELAY);
if (len > 0 && ppp) {
pppos_input_tcpip(ppp, buf, len);
}
}
}

/* IP events /
static void ip_event_handler(void
arg, esp_event_base_t base, int32_t id, void* data)
{
if (id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv4: " IPSTR, IP2STR(&ev->ip_info.ip));
} else if (id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *ev6 = (ip_event_got_ip6_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv6: " IPV6STR, IPV62STR(ev6->ip6_info.ip));
}
}

/* PDP bring-up on CID1 */
static bool setup_pdp_and_connect(void)
{
ESP_LOGI(TAG, “Setting PDP CID1 as %s and activating”, MODEM_PDP_TYPE);

// Basic init and disable echo/CMUX/hwflow on modem side
at_cmd("ATE0", 200);
at_cmd("AT+QCFG=\"dataformat\",0,0", 300); // disable CMUX

#if USE_HW_FLOWCTRL
at_cmd(“AT+IFC=2,2”, 300); // enable RTS/CTS if wired
#else
at_cmd(“AT+IFC=0,0”, 300); // disable hw flow control to match UART cfg
#endif
at_cmd(“AT+IPR=115200”, 300); // lock baud
at_cmd(“AT+CFUN=1”, 500);

// Wait for attach
if (!wait_for_attach(10, 1000)) {
    ESP_LOGE(TAG, "Modem not attached (+CGATT:0); aborting");
    return false;
}

char cmd[96];
snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"%s\",\"%s\"", MODEM_PDP_TYPE, APN);
at_cmd(cmd, 500);

at_cmd("AT+CGACT=1,1", 800);   // activate CID1
at_cmd_log("AT+CGACT?", 500);  // expect +CGACT: 1,1

// Confirm IP address
uart_flush_input(MODEM_UART);
at_cmd_log("AT+CGPADDR=1", 500); // should show an IP; if not, fail

// Dial PPP using CGDATA (preferred on Quectel)
uart_flush_input(MODEM_UART);
ESP_LOGI(TAG, "Dialing AT+CGDATA=\"PPP\",1 ...");
uart_write_bytes(MODEM_UART, "AT+CGDATA=\"PPP\",1\r", 18);
bool got_connect = wait_for_connect(10000);

if (!got_connect) {
    ESP_LOGE(TAG, "No CONNECT; aborting PPP start");
    return false;
}

// Allow modem to settle into data mode and drop the CONNECT text
vTaskDelay(pdMS_TO_TICKS(200));
uart_flush_input(MODEM_UART);
return true;

}

/* Start PPP */
static void start_pppos(void)
{
at_cmd_log(“AT+CPIN?”, 1000);
at_cmd_log(“AT+CSQ”, 1000);

bool connected = setup_pdp_and_connect();
if (!connected) {
    ESP_LOGE(TAG, "PDP/CONNECT failed; not starting PPP");
    return;
}

esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP();
esp_netif_ppp = esp_netif_new(&cfg);
assert(esp_netif_ppp);
esp_netif_attach(esp_netif_ppp, &ppp_netif);

ppp = pppapi_pppos_create(&ppp_netif, ppp_output_cb, ppp_status_cb, NULL);
if (!ppp) { ESP_LOGE(TAG, "pppos_create failed"); return; }

pppapi_set_default(ppp);
ppp_set_usepeerdns(ppp, 1);
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "", ""); // carrier-specific creds if required

xTaskCreatePinnedToCore(ppp_rx_task, "ppp_rx", 6144, NULL, 6, NULL, 1);

ESP_LOGI(TAG, "Calling pppapi_connect...");
pppapi_connect(ppp, 0);

}

/* MAIN */
void app_main(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL));

uart_init();
modem_power_on();
start_pppos();

for (;;) {
    vTaskDelay(pdMS_TO_TICKS(5000));
}

}

D (625) lwip: netif: GW address of interface set to 127.0.0.1

D (625) lwip: netif_set_ipaddr: netif address being changed

D (635) lwip: netif: added interface lo IP
D (635) lwip: addr
D (635) lwip: 127.0.0.1
D (635) lwip: netmask
D (645) lwip: 255.0.0.0
D (645) lwip: gw
D (645) lwip: 127.0.0.1
D (645) lwip:

D (655) esp_netif_lwip: LwIP stack has been initialized
D (655) esp_netif_lwip: esp-netif has been successfully initialized
D (665) event: running task for loop 0x3fcec0d8
D (665) event: created task for loop 0x3fcec0d8
D (665) event: created event loop 0x3fcec0d8
D (675) intr_alloc: Connected src 28 to int 8 (cpu 0)
I (8185) PPPOS_ONLY: AT+CPIN? rsp:
+CPIN: READY

OK

I (9195) PPPOS_ONLY: AT+CSQ rsp:
+CSQ: 19,99

OK

I (9995) PPPOS_ONLY: Setting PDP CID1 as IP and activating
I (12605) PPPOS_ONLY: AT+CGATT? rsp:
+CGATT: 1

OK

I (14115) PPPOS_ONLY: AT+CGACT? rsp:
+CGACT: 1,1

OK

I (14725) PPPOS_ONLY: AT+CGPADDR=1 rsp:
+CGPADDR: 1,“10.25.124.241”

OK

I (15125) PPPOS_ONLY: Dialing AT+CGDATA=“PPP”,1 …
I (15335) PPPOS_ONLY: MODEM:
CONNECT

D (15535) esp_netif_lwip: check: remote, if=0x3fc9a040 fn=0x4202bb08
— 0x4202bb08: esp_netif_new_api at D:/Espressif/frameworks/esp-idf-v5.5.1/components/esp_netif/lwip/esp_netif_lwip.c:769
D (15535) esp_netif_objects: esp_netif_add_to_list_unsafe netif added successfully (total netifs: 1)
D (15535) lwip: netif: netmask of interface set to 255.255.255.255

D (15545) lwip: netif: added interface pp IP
D (15545) lwip: addr
D (15545) lwip: 0.0.0.0
D (15545) lwip: netmask
D (15555) lwip: 255.255.255.255
D (15555) lwip: gw
D (15555) lwip: 0.0.0.0
D (15555) lwip:

D (15555) lwip: ppp phase changed[1]: phase=0

D (15565) esp-netif_lwip-ppp: esp_netif_new_ppp: PPP connection created: 0x3fcee888
D (15575) esp-netif_lwip-ppp: ppp: Phase Dead
D (15575) esp_netif_lwip: call api in lwip: ret=0x0, give sem
D (15585) lwip: netif: netmask of interface set to 255.255.255.255

D (15585) esp_netif_lwip: esp_netif_internal_dhcpc_cb lwip-netif:0x3fc96a80
D (15595) lwip: netif: added interface pp IP
D (15595) lwip: addr
D (15595) lwip: 0.0.0.0
D (15605) lwip: netmask
D (15605) lwip: 255.255.255.255
D (15605) lwip: gw
D (15605) lwip: 0.0.0.0
D (15615) lwip:

D (15615) lwip: ppp phase changed[2]: phase=0

D (15615) lwip: netif: setting default interface pp

I (15625) PPPOS_ONLY: Calling pppapi_connect…
D (15625) lwip: ppp_connect[2]: holdoff=0

D (15635) lwip: ppp phase changed[2]: phase=3

D (15635) lwip: pppos_connect: unit 2: connecting

D (15635) lwip: ppp_start[2]

D (15645) lwip: ppp phase changed[2]: phase=6

D (15645) lwip: ppp_send_config[2]

D (15645) lwip: pppos_send_config[2]: out_accm=FF FF FF FF

D (15655) lwip: ppp_recv_config[2]

D (15655) lwip: pppos_recv_config[2]: in_accm=FF FF FF FF

D (15665) lwip: ppp: auth protocols:
D (15665) lwip: PAP=1
D (15665) lwip: CHAP=1 CHAP_MD5=1
D (15675) lwip:

D (15675) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (15685) lwip: pppos_write[2]: len=24

D (15685) lwip: ppp_start[2]: finished

D (21685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (21685) lwip: pppos_write[2]: len=24

D (27685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (27685) lwip: pppos_write[2]: len=24

D (33685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (33685) lwip: pppos_write[2]: len=24

D (39685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (39685) lwip: pppos_write[2]: len=24

D (45685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (45685) lwip: pppos_write[2]: len=24

D (51685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (51685) lwip: pppos_write[2]: len=24

D (57685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (57685) lwip: pppos_write[2]: len=24

D (63685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (63685) lwip: pppos_write[2]: len=24

D (69685) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x293828a3> ]

D (69685) lwip: pppos_write[2]: len=24

D (75685) lwip: LCP: timeout sending Config-Requests

D (75685) lwip: ppp phase changed[2]: phase=12

D (75685) lwip: Connection terminated.

D (75685) lwip: ppp_link_terminated[2]

D (75685) lwip: ppp_link_end[2]

D (75685) lwip: ppp phase changed[2]: phase=0

E (75695) PPPOS_ONLY: PPP ERROR: 6
D (75695) lwip: ppp_link_terminated[2]: finished.

pppos_test.c (8.1 KB)

Looking forward for your responce .
Thanks and regards
vignesh sai

Hi Vignesh,

Glad to hear that you have made progress. The issue where the modem returns CONNECT but never responds to the LCP configuration requests is most often caused by a conflict between the modem’s internal IP stack and the external PPP stack on your ESP32.

Your code explicitly calls at_cmd(“AT+CGACT=1,1”, 800); to activate the PDP context and then checks the IP with AT+CGPADDR=1. By doing this, the modem’s internal communication processor has already “consumed” the IP address and established its own internal data session for CID 1. When you subsequently dial AT+CGDATA=“PPP”,1, the modem switches the UART to data mode (returning CONNECT), but because the context is already active internally, it often fails to bridge the raw PPP frames from the UART to the network. The modem’s PPP engine is essentially starved because the internal stack is already holding the session.

To fix this, remove AT+CGACT=1,1 and AT+CGPADDR=1 from your initialization sequence. Use AT+CGDCONT to define the APN, then jump directly to the dialing command (ATD*99# or AT+CGDATA). This allows the dialing command to handle the activation and correctly bridge the data stream to your ESP32.

I see that you use uart_flush_input(MODEM_UART); after receiving the CONNECT string. If the modem sends the first LCP ConfReq (Modem → ESP32) immediately after the CONNECT string, your flush command might be deleting the modem’s initial negotiation frame before the LwIP stack can see it. I recommend you reduce the vTaskDelay after CONNECT and ensure that the ppp_rx_task is already running and ready to process bytes the moment the UART switches modes.

Even though you have set USE_HW_FLOWCTRL 0, ensure the modem is strictly obeying this. You are correctly sending AT+IFC=0,0 to disable hardware flow control on the modem side. If the modem firmware expects a high DSR or DTR signal to begin transmitting data frames, it will remain silent regardless of the LCP requests it receives. Try sending AT&D0 and AT&S0 during your setup sequence to ensure the modem does not wait for hardware signals that your 2-wire TX/RX setup cannot provide.

Please try these things i mentioned and let me know if it resolves the issue.

Thanks!
Have a great day!

Best Regards,
Ananthan

Hi Ananthan , Thanks for the brief again.

As considering and implimented the above things, Still the modem does’nt respond to the lcp .
Kindly find the new logs.

#include <string.h>
#include <stdio.h>

#include “freertos/FreeRTOS.h”
#include “freertos/task.h”

#include “driver/uart.h”
#include “driver/gpio.h”

#include “netif/ppp/pppapi.h”
#include “netif/ppp/pppos.h”
#include “netif/ppp/ppp.h”
#include “lwip/netif.h”
#include “lwip/sockets.h”
#include “lwip/inet.h”

#include “esp_log.h”
#include “esp_event.h”
#include “esp_netif.h”

// Set to 1 if you wire RTS/CTS and set modem IFC=2,2; otherwise keep 0 (TX/RX only).
#define USE_HW_FLOWCTRL 0

#define MODEM_UART UART_NUM_1
#define UART_TX_PIN 37 // adjust to your wiring
#define UART_RX_PIN 36 // adjust to your wiring
#define UART_BAUDRATE 115200
#define MODEM_PWRKEY 1 // adjust if your PWRKEY is another GPIO
#define APN “www” // Vi India APN is “www”; change if needed
#define MODEM_PDP_TYPE “IP” // use “IP” or “IPV4V6” if needed

static const char *TAG = “PPPOS_ONLY”;
static ppp_pcb *ppp;
static struct netif ppp_netif;
static esp_netif_t *esp_netif_ppp;

/* UART init */
static void uart_init(void)
{
uart_config_t cfg = {
.baud_rate = UART_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
#if USE_HW_FLOWCTRL
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.rx_flow_ctrl_thresh = 64,
#else
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
#endif
};
uart_driver_install(MODEM_UART, 4096, 4096, 0, NULL, 0);
uart_param_config(MODEM_UART, &cfg);
uart_set_pin(MODEM_UART, UART_TX_PIN, UART_RX_PIN,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#if USE_HW_FLOWCTRL
uart_set_hw_flow_ctrl(MODEM_UART, UART_HW_FLOWCTRL_CTS_RTS, 64);
#endif
}

/* Modem power pulse */
static void modem_power_on(void)
{
gpio_set_direction(MODEM_PWRKEY, GPIO_MODE_OUTPUT);
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(MODEM_PWRKEY, 0);
vTaskDelay(pdMS_TO_TICKS(1200));
gpio_set_level(MODEM_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(6000));
}

/* AT helpers */
static void at_cmd(const char *cmd, int delay_ms)
{
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}

static void at_cmd_log(const char *cmd, int collect_ms)
{
uint8_t buf[256];
uart_flush_input(MODEM_UART);
uart_write_bytes(MODEM_UART, cmd, strlen(cmd));
uart_write_bytes(MODEM_UART, “\r”, 1);
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(collect_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “%s rsp: %s”, cmd, buf);
}
}
}

/* Wait for CONNECT /
static bool wait_for_connect(int timeout_ms)
{
uint8_t buf[256];
TickType_t start = xTaskGetTickCount();
while ((xTaskGetTickCount() - start) < pdMS_TO_TICKS(timeout_ms)) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, 200 / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “MODEM: %s”, buf);
if (strstr((char
)buf, “CONNECT”)) return true;
if (strstr((char*)buf, “ERROR”) || strstr((char*)buf, “NO CARRIER”)) return false;
}
}
ESP_LOGE(TAG, “Timed out waiting for CONNECT”);
return false;
}

/* Wait for +CGATT: 1 /
static bool wait_for_attach(int max_checks, int interval_ms)
{
for (int i = 0; i < max_checks; ++i) {
uint8_t buf[128];
uart_flush_input(MODEM_UART);
uart_write_bytes(MODEM_UART, “AT+CGATT?\r”, 10);
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf) - 1, interval_ms / portTICK_PERIOD_MS);
if (len > 0) {
buf[len] = 0;
ESP_LOGI(TAG, “AT+CGATT? rsp: %s”, buf);
if (strstr((char
)buf, “+CGATT: 1”)) {
return true;
}
}
}
return false;
}

/* PPP callbacks */
static u32_t ppp_output_cb(ppp_pcb *pcb, const void *data, u32_t len, void *ctx)
{
uart_write_bytes(MODEM_UART, (const char *)data, len);
return len;
}

static void ppp_status_cb(ppp_pcb *pcb, int err, void *ctx)
{
if (err == PPPERR_NONE) ESP_LOGI(TAG, “PPP CONNECTED”);
else ESP_LOGE(TAG, “PPP ERROR: %d”, err);
}

/* PPP RX task */
static void ppp_rx_task(void *arg)
{
uint8_t buf[1520];
while (1) {
int len = uart_read_bytes(MODEM_UART, buf, sizeof(buf), portMAX_DELAY);
if (len > 0 && ppp) {
pppos_input_tcpip(ppp, buf, len);
}
}
}

/* IP events /
static void ip_event_handler(void
arg, esp_event_base_t base, int32_t id, void* data)
{
if (id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *ev = (ip_event_got_ip_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv4: " IPSTR, IP2STR(&ev->ip_info.ip));
} else if (id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *ev6 = (ip_event_got_ip6_t *)data;
ESP_LOGI(TAG, "PPP GOT IPv6: " IPV6STR, IPV62STR(ev6->ip6_info.ip));
}
}

/* Dial PPP (no pre-activation) */
static bool setup_pdp_and_connect(void)
{
ESP_LOGI(TAG, “Setting PDP CID1 as %s”, MODEM_PDP_TYPE);

// Basic init; ignore if dataformat errors
at_cmd("ATE0", 200);
at_cmd("AT+QCFG=\"dataformat\",0,0", 200);

#if USE_HW_FLOWCTRL
at_cmd(“AT+IFC=2,2”, 200);
#else
at_cmd(“AT+IFC=0,0”, 200);
#endif
at_cmd(“AT+IPR=115200”, 200);
at_cmd(“AT&D0”, 200);
at_cmd(“AT&S0”, 200);
at_cmd(“AT+QIDEACT=1”, 400);
at_cmd(“AT+CFUN=1”, 500);

// Wait for attach
if (!wait_for_attach(10, 1000)) {
    ESP_LOGE(TAG, "Modem not attached (+CGATT:0); aborting");
    return false;
}

// Define PDP; do NOT CGACT/CGPADDR here
char cmd[96];
snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"%s\",\"%s\"", MODEM_PDP_TYPE, APN);
at_cmd(cmd, 400);

// Dial PPP (let modem activate PDP)
uart_flush_input(MODEM_UART);
ESP_LOGI(TAG, "Dialing AT+CGDATA=\"PPP\",1 ...");
uart_write_bytes(MODEM_UART, "AT+CGDATA=\"PPP\",1\r", 18);
bool got_connect = wait_for_connect(10000);
if (!got_connect) {
    ESP_LOGE(TAG, "No CONNECT; aborting PPP start");
    return false;
}

// Tiny delay; do NOT flush here to avoid dropping first LCP
vTaskDelay(pdMS_TO_TICKS(50));
return true;

}

/* Start PPP */
static void start_pppos(void)
{
at_cmd_log(“AT+CPIN?”, 800);
at_cmd_log(“AT+CSQ”, 800);

bool connected = setup_pdp_and_connect();
if (!connected) {
    ESP_LOGE(TAG, "PDP/CONNECT failed; not starting PPP");
    return;
}

esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP();
esp_netif_ppp = esp_netif_new(&cfg);
assert(esp_netif_ppp);
esp_netif_attach(esp_netif_ppp, &ppp_netif);

ppp = pppapi_pppos_create(&ppp_netif, ppp_output_cb, ppp_status_cb, NULL);
if (!ppp) { ESP_LOGE(TAG, "pppos_create failed"); return; }

pppapi_set_default(ppp);
ppp_set_usepeerdns(ppp, 1);
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "", ""); // empty creds; change if carrier needs

xTaskCreatePinnedToCore(ppp_rx_task, "ppp_rx", 6144, NULL, 6, NULL, 1);

ESP_LOGI(TAG, "Calling pppapi_connect...");
pppapi_connect(ppp, 0);

}

/* MAIN */
void app_main(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL));

uart_init();
modem_power_on();
start_pppos();

for (;;) {
    vTaskDelay(pdMS_TO_TICKS(5000));
}

}

Output logs.

b_serial_jtag_connection_monitor.c:75
D (570) cpu_start: calling init function: 0x42002fc0 on core: 0
— 0x42002fc0: __esp_system_init_fn_init_disable_rtc_wdt at D:/Espressif/frameworks/esp-idf-v5.5.1/components/esp_system/startup_funcs.c:179
D (576) intr_alloc: Connected src 79 to int 2 (cpu 0)
D (581) app_start: Starting scheduler on CPU0
D (585) intr_alloc: Connected src 57 to int 3 (cpu 0)
D (585) intr_alloc: Connected src 80 to int 0 (cpu 1)
D (585) app_start: Starting scheduler on CPU1
D (595) intr_alloc: Connected src 58 to int 1 (cpu 1)
I (585) main_task: Started on CPU0
D (605) heap_init: New heap initialised at 0x3fce9710
D (605) intr_alloc: Connected src 52 to int 5 (cpu 0)
I (615) main_task: Calling app_main()
D (615) lwip: netif: netmask of interface set to 255.0.0.0

D (625) lwip: netif: GW address of interface set to 127.0.0.1

D (625) lwip: netif_set_ipaddr: netif address being changed

D (635) lwip: netif: added interface lo IP
D (635) lwip: addr
D (635) lwip: 127.0.0.1
D (635) lwip: netmask
D (645) lwip: 255.0.0.0
D (645) lwip: gw
D (645) lwip: 127.0.0.1
D (645) lwip:

D (655) esp_netif_lwip: LwIP stack has been initialized
D (655) esp_netif_lwip: esp-netif has been successfully initialized
D (665) event: running task for loop 0x3fcec0d8
D (665) event: created task for loop 0x3fcec0d8
D (665) event: created event loop 0x3fcec0d8
D (675) intr_alloc: Connected src 28 to int 8 (cpu 0)
I (8185) PPPOS_ONLY: AT+CPIN? rsp:
+CPIN: READY

OK

I (8995) PPPOS_ONLY: AT+CSQ rsp:
+CSQ: 16,99

OK

I (9595) PPPOS_ONLY: Setting PDP CID1 as IP
I (12705) PPPOS_ONLY: AT+CGATT? rsp:
+CGATT: 1

OK

I (13105) PPPOS_ONLY: Dialing AT+CGDATA=“PPP”,1 …
I (13315) PPPOS_ONLY: MODEM:
CONNECT

D (13365) esp_netif_lwip: check: remote, if=0x3fc9a040 fn=0x4202bafc
— 0x4202bafc: esp_netif_new_api at D:/Espressif/frameworks/esp-idf-v5.5.1/components/esp_netif/lwip/esp_netif_lwip.c:769
D (13365) esp_netif_objects: esp_netif_add_to_list_unsafe netif added successfully (total netifs: 1)
D (13365) lwip: netif: netmask of interface set to 255.255.255.255

D (13375) lwip: netif: added interface pp IP
D (13375) lwip: addr
D (13375) lwip: 0.0.0.0
D (13375) lwip: netmask
D (13385) lwip: 255.255.255.255
D (13385) lwip: gw
D (13385) lwip: 0.0.0.0
D (13385) lwip:

D (13385) lwip: ppp phase changed[1]: phase=0

D (13395) esp-netif_lwip-ppp: esp_netif_new_ppp: PPP connection created: 0x3fcee888
D (13405) esp-netif_lwip-ppp: ppp: Phase Dead
D (13405) esp_netif_lwip: call api in lwip: ret=0x0, give sem
D (13415) lwip: netif: netmask of interface set to 255.255.255.255

D (13415) esp_netif_lwip: esp_netif_internal_dhcpc_cb lwip-netif:0x3fc96a80
D (13425) lwip: netif: added interface pp IP
D (13425) lwip: addr
D (13425) lwip: 0.0.0.0
D (13435) lwip: netmask
D (13435) lwip: 255.255.255.255
D (13435) lwip: gw
D (13435) lwip: 0.0.0.0
D (13445) lwip:

D (13445) lwip: ppp phase changed[2]: phase=0

D (13445) lwip: netif: setting default interface pp

I (13455) PPPOS_ONLY: Calling pppapi_connect…
D (13455) lwip: ppp_connect[2]: holdoff=0

D (13465) lwip: ppp phase changed[2]: phase=3

D (13465) lwip: pppos_connect: unit 2: connecting

D (13465) lwip: ppp_start[2]

D (13475) lwip: ppp phase changed[2]: phase=6

D (13475) lwip: ppp_send_config[2]

D (13475) lwip: pppos_send_config[2]: out_accm=FF FF FF FF

D (13485) lwip: ppp_recv_config[2]

D (13485) lwip: pppos_recv_config[2]: in_accm=FF FF FF FF

D (13495) lwip: ppp: auth protocols:
D (13495) lwip: PAP=1
D (13495) lwip: CHAP=1 CHAP_MD5=1
D (13505) lwip:

D (13505) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (13515) lwip: pppos_write[2]: len=24

D (13515) lwip: ppp_start[2]: finished

D (19515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (19515) lwip: pppos_write[2]: len=24

D (25515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (25515) lwip: pppos_write[2]: len=24

D (31515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (31515) lwip: pppos_write[2]: len=24

D (37515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (37515) lwip: pppos_write[2]: len=24

D (43515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (43515) lwip: pppos_write[2]: len=24

D (49515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (49515) lwip: pppos_write[2]: len=24

D (55515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (55515) lwip: pppos_write[2]: len=24

D (61515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (61515) lwip: pppos_write[2]: len=24

D (67515) lwip: sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x4b258cac> ]

D (67515) lwip: pppos_write[2]: len=24

D (73515) lwip: LCP: timeout sending Config-Requests

D (73515) lwip: ppp phase changed[2]: phase=12

D (73515) lwip: Connection terminated.

D (73515) lwip: ppp_link_terminated[2]

D (73515) lwip: ppp_link_end[2]

D (73515) lwip: ppp phase changed[2]: phase=0

E (73525) PPPOS_ONLY: PPP ERROR: 6
D (73525) lwip: ppp_link_terminated[2]: finished.

Done

pppos_test.c (7.7 KB)

Thanks and Regards.

Hi Vignesh,

Thanks for sharing the full log.

From the log, the ESP32 side is working correctly. The modem replies CONNECT, and the ESP32 keeps sending PPP LCP requests, but the modem never sends anything back. Because of this, LCP times out and the PPP session closes.

This usually happens due to modem-side conditions, not ESP-IDF or lwIP.

Please try the following (in this order):

  1. DTR pin
  • Make sure the modem DTR pin is not floating.
  • Tie the DTR pin to GND (or the required active level).
  • This is very important for data mode to work properly.
  1. Change dial command
  • Instead of
    AT+CGDATA=“PPP”,1
    try
    ATD*99#
  1. Remove dataformat setting
  • If AT+QCFG=“dataformat” is used, please remove it and power-cycle the modem.

Right now, the issue is that the modem enters data mode but does not forward PPP data on the UART. Once the DTR and dial command are corrected, the modem should start responding to LCP immediately.

Please try the above and let me know the result.

Thanks!

Best Regards,
Ananthan