uqmid: modem: handle modem with auto connect
authorAlexander Couzens <[email protected]>
Wed, 14 Aug 2024 12:44:37 +0000 (14:44 +0200)
committerDavid Bauer <[email protected]>
Sat, 31 May 2025 20:41:00 +0000 (22:41 +0200)
When a modem has WDS auto connect enabled,
a start network will result in the error "No Effect".
Stop the auto connection and start it to get the packet handle.

Signed-off-by: Alexander Couzens <[email protected]>
uqmid/modem_fsm.c
uqmid/modem_fsm.h
uqmid/modem_tx.c
uqmid/modem_tx.h

index 045f82c5a98d2c68a0ea5e19d7ad3d4ec3083db1..bd4ec8ea739d9caa277c172fbe06887a535b7941 100644 (file)
@@ -1,4 +1,6 @@
 
+#include <assert.h>
+
 #include "osmocom/fsm.h"
 #include "osmocom/utils.h"
 
@@ -68,6 +70,8 @@ static const struct value_string modem_event_names[] = {
        { MODEM_EV_RX_SUBSCRIBED,               "RX_SUBSCRIBED" },
        { MODEM_EV_RX_SUBSCRIBE_FAILED,         "RX_SUBSCRIBE_FAILED" },
 
+       { MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS, "RX_DISABLE_AUTOCONNECT_SUCCESS"},
+
        { MODEM_EV_RX_FAILED,                   "RX_FAILED" },
        { MODEM_EV_RX_SUCCEED,                  "RX_SUCCEED" },
        { 0, NULL }
@@ -805,6 +809,22 @@ static void wds_start_network_cb(struct qmi_service *service, struct qmi_request
        }
 }
 
+static void
+wds_stop_network_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
+{
+       struct modem *modem = req->cb_data;
+       int ret;
+
+       ret = qmi_parse_wds_stop_network_response(msg);
+       if (ret) {
+               modem_log(modem, LOGL_INFO, "Failed to stop network.");
+               osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
+               return;
+       }
+
+       osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS, NULL);
+}
+
 static void modem_st_start_iface_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
 {
        struct modem *modem = fi->priv;
@@ -816,15 +836,31 @@ static void modem_st_start_iface(struct osmo_fsm_inst *fi, uint32_t event, void
 {
        struct modem *modem = fi->priv;
        long reason;
+       bool disable_autoconnect = true;
+       struct qmi_service *wds = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
+       /* FIXME: ensure essential services "can't" disappear or abort the FSM nicely */
+       assert(wds);
 
        switch (event) {
+       case MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS:
+               tx_wds_start_network(modem, wds, wds_start_network_cb, modem->qmi->wds.profile_id, modem->qmi->wds.ip_family);
+               break;
        case MODEM_EV_RX_FAILED:
-               reason = (long)data;
-               if (reason == QMI_PROTOCOL_ERROR_CALL_FAILED) {
+               reason = (long) data;
+               switch (reason) {
+               case QMI_PROTOCOL_ERROR_CALL_FAILED:
                        fi->T = N_RESEND;
-               } else {
+                       break;
+               case QMI_PROTOCOL_ERROR_NO_EFFECT:
+                       /* No effect means it already started a connection,
+                        * but we didn't got packet_data_handle out of it.
+                        */
+                       tx_wds_stop_network(modem, wds, wds_stop_network_cb, 0xffffffff, &disable_autoconnect);
+                       break;
+               default:
                        uqmid_modem_set_error(modem, "Start Iface/Network failed!");
                        osmo_fsm_inst_state_chg(fi, MODEM_ST_POWEROFF, 0, 0);
+                       break;
                }
                break;
        case MODEM_EV_RX_SUCCEED:
@@ -1115,7 +1151,8 @@ static const struct osmo_fsm_state modem_states[] = {
        },
        [MODEM_ST_START_IFACE] = {
                .in_event_mask = S(MODEM_EV_RX_SUCCEED)
-                                | S(MODEM_EV_RX_FAILED),
+                                | S(MODEM_EV_RX_FAILED)
+                                | S(MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS),
                .out_state_mask = S(MODEM_ST_LIVE) | S(MODEM_ST_DESTROY) | S(MODEM_ST_POWEROFF),
                .name = "START_IFACE",
                .action = modem_st_start_iface,
index 50f45e87d140fdd8be8fc9756f05b8924fec2cda..2fc874c33d76b9f6e1a1c80ba5438dbe4b15d01b 100644 (file)
@@ -50,6 +50,8 @@ enum modem_fsm_event {
        MODEM_EV_RX_SUBSCRIBED,
        MODEM_EV_RX_SUBSCRIBE_FAILED,
 
+       MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS,
+
        MODEM_EV_RX_FAILED,
        MODEM_EV_RX_SUCCEED, /* a generic callback succeeded */
        MODEM_EV_REQ_DESTROY,
index caf2072bfb27a4c2e8048df9fb2d8f62b7b5f953..9ebd4a178d8de6927845b65d22cdc4497c79d7c3 100644 (file)
@@ -185,7 +185,7 @@ int tx_wds_start_network(struct modem *modem, struct qmi_service *wds, request_c
        return uqmi_service_send_msg(wds, req);
 }
 
-int tx_wds_stop_network(struct modem *modem, struct qmi_service *wds, request_cb cb, uint32_t *packet_data_handle,
+int tx_wds_stop_network(struct modem *modem, struct qmi_service *wds, request_cb cb, uint32_t packet_data_handle,
                        bool *disable_autoconnect)
 {
        struct qmi_request *req = talloc_zero(wds, struct qmi_request);
@@ -193,8 +193,7 @@ int tx_wds_stop_network(struct modem *modem, struct qmi_service *wds, request_cb
 
        struct qmi_wds_stop_network_request stop_req = {};
 
-       if (packet_data_handle)
-               qmi_set(&stop_req, packet_data_handle, *packet_data_handle);
+       qmi_set(&stop_req, packet_data_handle, packet_data_handle);
 
        if (disable_autoconnect)
                qmi_set(&stop_req, disable_autoconnect, *disable_autoconnect);
index 17a30ea9b399fdbab429873e792a0d9406b80cf8..872ebe635e4d8a0c3b74dccd6efbd3d40bd1d689 100644 (file)
@@ -18,7 +18,7 @@ int tx_wds_modify_profile(struct modem *modem, struct qmi_service *wds, request_
                          uint8_t pdp_type, const char *username, const char *password);
 int tx_wds_start_network(struct modem *modem, struct qmi_service *wds, request_cb cb, uint8_t profile_idx,
                         uint8_t ip_family);
-int tx_wds_stop_network(struct modem *modem, struct qmi_service *wds, request_cb cb, uint32_t *packet_data_handle,
+int tx_wds_stop_network(struct modem *modem, struct qmi_service *wds, request_cb cb, uint32_t packet_data_handle,
                        bool *disable_autoconnect);
 int tx_wds_get_current_settings(struct modem *modem, struct qmi_service *wds, request_cb cb);