diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index adc66f574b7..1d15350b48e 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -13,6 +13,7 @@ config MODEM_CELLULAR select RING_BUFFER select NET_L2_PPP_OPTION_MRU select NET_L2_PPP_PAP + select NET_L2_PPP_MGMT depends on (DT_HAS_QUECTEL_BG95_ENABLED || \ DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ DT_HAS_U_BLOX_SARA_R5_ENABLED || DT_HAS_SWIR_HL7800_ENABLED || \ diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index 2af67a01c7a..7ca2001697f 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -60,6 +60,7 @@ enum modem_cellular_state { MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT, MODEM_CELLULAR_STATE_AWAIT_REGISTERED, MODEM_CELLULAR_STATE_CARRIER_ON, + MODEM_CELLULAR_STATE_DORMANT, MODEM_CELLULAR_STATE_INIT_POWER_OFF, MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT, MODEM_CELLULAR_STATE_POWER_OFF_PULSE, @@ -79,6 +80,7 @@ enum modem_cellular_event { MODEM_CELLULAR_EVENT_DEREGISTERED, MODEM_CELLULAR_EVENT_BUS_OPENED, MODEM_CELLULAR_EVENT_BUS_CLOSED, + MODEM_CELLULAR_EVENT_PPP_DEAD, }; struct modem_cellular_data { @@ -126,6 +128,7 @@ struct modem_cellular_data { /* PPP */ struct modem_ppp *ppp; + struct net_mgmt_event_callback net_mgmt_event_callback; enum modem_cellular_state state; const struct device *dev; @@ -196,6 +199,8 @@ static const char *modem_cellular_state_str(enum modem_cellular_state state) return "run dial script"; case MODEM_CELLULAR_STATE_CARRIER_ON: return "carrier on"; + case MODEM_CELLULAR_STATE_DORMANT: + return "dormant"; case MODEM_CELLULAR_STATE_INIT_POWER_OFF: return "init power off"; case MODEM_CELLULAR_STATE_RUN_SHUTDOWN_SCRIPT: @@ -236,6 +241,8 @@ static const char *modem_cellular_event_str(enum modem_cellular_event event) return "bus opened"; case MODEM_CELLULAR_EVENT_BUS_CLOSED: return "bus closed"; + case MODEM_CELLULAR_EVENT_PPP_DEAD: + return "ppp dead"; } return ""; @@ -1021,7 +1028,9 @@ static void modem_cellular_run_dial_script_event_handler(struct modem_cellular_d modem_chat_attach(&data->chat, data->dlci1_pipe); modem_chat_run_script_async(&data->chat, config->dial_chat_script); break; - + case MODEM_CELLULAR_EVENT_SCRIPT_FAILED: + modem_cellular_start_timer(data, MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT); + break; case MODEM_CELLULAR_EVENT_SCRIPT_SUCCESS: modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_REGISTERED); break; @@ -1110,7 +1119,7 @@ static void modem_cellular_carrier_on_event_handler(struct modem_cellular_data * break; case MODEM_CELLULAR_EVENT_DEREGISTERED: - modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT); + modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_DORMANT); break; case MODEM_CELLULAR_EVENT_SUSPEND: @@ -1125,9 +1134,37 @@ static void modem_cellular_carrier_on_event_handler(struct modem_cellular_data * static int modem_cellular_on_carrier_on_state_leave(struct modem_cellular_data *data) { modem_cellular_stop_timer(data); + + return 0; +} + +static int modem_cellular_on_dormant_state_enter(struct modem_cellular_data *data) +{ + net_if_dormant_on(modem_ppp_get_iface(data->ppp)); + + return 0; +} + +static void modem_cellular_dormant_event_handler(struct modem_cellular_data *data, + enum modem_cellular_event evt) +{ + switch (evt) { + case MODEM_CELLULAR_EVENT_PPP_DEAD: + modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_RUN_DIAL_SCRIPT); + break; + + default: + break; + } +} + +static int modem_cellular_on_dormant_state_leave(struct modem_cellular_data *data) +{ net_if_carrier_off(modem_ppp_get_iface(data->ppp)); modem_chat_release(&data->chat); modem_ppp_release(data->ppp); + net_if_dormant_off(modem_ppp_get_iface(data->ppp)); + return 0; } @@ -1316,6 +1353,10 @@ static int modem_cellular_on_state_enter(struct modem_cellular_data *data) ret = modem_cellular_on_carrier_on_state_enter(data); break; + case MODEM_CELLULAR_STATE_DORMANT: + ret = modem_cellular_on_dormant_state_enter(data); + break; + case MODEM_CELLULAR_STATE_INIT_POWER_OFF: ret = modem_cellular_on_init_power_off_state_enter(data); break; @@ -1377,6 +1418,10 @@ static int modem_cellular_on_state_leave(struct modem_cellular_data *data) ret = modem_cellular_on_carrier_on_state_leave(data); break; + case MODEM_CELLULAR_STATE_DORMANT: + ret = modem_cellular_on_dormant_state_leave(data); + break; + case MODEM_CELLULAR_STATE_INIT_POWER_OFF: ret = modem_cellular_on_init_power_off_state_leave(data); break; @@ -1476,6 +1521,10 @@ static void modem_cellular_event_handler(struct modem_cellular_data *data, modem_cellular_carrier_on_event_handler(data, evt); break; + case MODEM_CELLULAR_STATE_DORMANT: + modem_cellular_dormant_event_handler(data, evt); + break; + case MODEM_CELLULAR_STATE_INIT_POWER_OFF: modem_cellular_init_power_off_event_handler(data, evt); break; @@ -1719,6 +1768,22 @@ static int modem_cellular_pm_action(const struct device *dev, enum pm_device_act } #endif /* CONFIG_PM_DEVICE */ +static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + struct modem_cellular_data *data = + CONTAINER_OF(cb, struct modem_cellular_data, net_mgmt_event_callback); + + switch (mgmt_event) { + case NET_EVENT_PPP_PHASE_DEAD: + modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_PPP_DEAD); + break; + + default: + break; + } +} + static int modem_cellular_init(const struct device *dev) { struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; @@ -1827,6 +1892,13 @@ static int modem_cellular_init(const struct device *dev) modem_chat_init(&data->chat, &chat_config); } + { + net_mgmt_init_event_callback(&data->net_mgmt_event_callback, net_mgmt_event_handler, + NET_EVENT_PPP_PHASE_DEAD); + net_mgmt_add_event_callback(&data->net_mgmt_event_callback); + } + + #ifndef CONFIG_PM_DEVICE modem_cellular_delegate_event(data, MODEM_CELLULAR_EVENT_RESUME); #else diff --git a/subsys/net/l2/ppp/ppp_l2.c b/subsys/net/l2/ppp/ppp_l2.c index b9edd2629ce..5521d76470e 100644 --- a/subsys/net/l2/ppp/ppp_l2.c +++ b/subsys/net/l2/ppp/ppp_l2.c @@ -238,6 +238,19 @@ static int ppp_up(struct net_if *iface) return 0; } +static void ppp_lcp_close_async(struct ppp_context *ctx) +{ + if (ppp_lcp == NULL) { + ppp_change_phase(ctx, PPP_DEAD); + } + + if (ctx->phase == PPP_DEAD) { + return; + } + + ppp_lcp->close(ctx, "L2 Disabled"); +} + static int ppp_lcp_close(struct ppp_context *ctx) { if (ppp_lcp == NULL) { @@ -486,6 +499,10 @@ static void net_ppp_mgmt_evt_handler(struct net_mgmt_event_callback *cb, uint32_ if ((mgmt_event == NET_EVENT_IF_DOWN) && (!net_if_is_carrier_ok(iface))) { ppp_lcp_lower_down_async(ctx); } + if ((mgmt_event == NET_EVENT_IF_DOWN && net_if_is_carrier_ok(iface) && + net_if_is_dormant(iface))) { + ppp_lcp_close_async(ctx); + } } void net_ppp_init(struct net_if *iface)