drivers: gsm: Wait for NET_EVENT_IF_DOWN in in gsm_ppp_stop

Waits until the network interface goes down before switching the
GSM_MUX. It uses the NET_MGMT_EVENT to signal a semaphore to
contiue when closed. This allows for the LCP state machine to
properly terminate. When skipping this wait, the second time
connecting, the connection might fail.
Tested on a real modem.

Fixes GSM PPP behavior in combination with: #41802

Signed-off-by: Sjors Hettinga <s.a.hettinga@gmail.com>
This commit is contained in:
Sjors Hettinga 2022-01-21 16:17:07 +01:00 committed by Anas Nashif
commit 60beb291df
2 changed files with 32 additions and 0 deletions

View file

@ -6,6 +6,8 @@ config MODEM_GSM_PPP
select MODEM_CONTEXT
select MODEM_CMD_HANDLER
select MODEM_IFACE_UART
select NET_MGMT
select NET_MGMT_EVENT
help
Enable GSM modems that support standard AT commands and PPP.

View file

@ -65,6 +65,7 @@ static struct gsm_modem {
struct modem_cmd_handler_data cmd_handler_data;
uint8_t cmd_match_buf[GSM_CMD_READ_BUF];
struct k_sem sem_response;
struct k_sem sem_if_down;
struct modem_iface_uart_data gsm_data;
struct k_work_delayable gsm_configure_work;
@ -97,6 +98,7 @@ static struct gsm_modem {
gsm_modem_power_cb modem_on_cb;
gsm_modem_power_cb modem_off_cb;
struct net_mgmt_event_callback gsm_mgmt_cb;
} gsm;
NET_BUF_POOL_DEFINE(gsm_recv_pool, GSM_RECV_MAX_BUF, GSM_RECV_BUF_SIZE,
@ -1058,6 +1060,9 @@ void gsm_ppp_stop(const struct device *dev)
net_if_l2(iface)->enable(iface, false);
/* wait for the interface to be properly down */
(void)k_sem_take(&gsm->sem_if_down, K_FOREVER);
if (IS_ENABLED(CONFIG_GSM_MUX)) {
/* Lower mux_enabled flag to trigger re-sending AT+CMUX etc */
gsm->mux_enabled = false;
@ -1097,6 +1102,26 @@ const struct gsm_ppp_modem_info *gsm_ppp_modem_info(const struct device *dev)
return &gsm->minfo;
}
static void gsm_mgmt_event_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event, struct net_if *iface)
{
if ((mgmt_event & NET_EVENT_IF_DOWN) != mgmt_event) {
return;
}
/* Right now we only support 1 GSM instance */
if (iface != gsm.iface) {
return;
}
if (mgmt_event == NET_EVENT_IF_DOWN) {
LOG_INF("GSM network interface down");
/* raise semaphore to indicate the interface is down */
k_sem_give(&gsm.sem_if_down);
return;
}
}
static int gsm_init(const struct device *dev)
{
struct gsm_modem *gsm = dev->data;
@ -1115,6 +1140,7 @@ static int gsm_init(const struct device *dev)
gsm->cmd_handler_data.eol = "\r";
k_sem_init(&gsm->sem_response, 0, 1);
k_sem_init(&gsm->sem_if_down, 0, 1);
r = modem_cmd_handler_init(&gsm->context.cmd_handler,
&gsm->cmd_handler_data);
@ -1174,6 +1200,10 @@ static int gsm_init(const struct device *dev)
return -ENODEV;
}
net_mgmt_init_event_callback(&gsm->gsm_mgmt_cb, gsm_mgmt_event_handler,
NET_EVENT_IF_DOWN);
net_mgmt_add_event_callback(&gsm->gsm_mgmt_cb);
if (IS_ENABLED(CONFIG_GSM_PPP_AUTOSTART)) {
gsm_ppp_start(dev);
}