diff mbox series

[v2,09/11] qmi: gprs-context: refactor detach_shutdown path

Message ID 20240711164936.1688973-9-denkenz@gmail.com (mailing list archive)
State Accepted
Commit d617baf9e089b9da2055690d568d52f320136d08
Headers show
Series [v2,01/11] gobi: Limit number of premultiplexed contexts to 4 | expand

Commit Message

Denis Kenzior July 11, 2024, 4:49 p.m. UTC
Since there will now be up to two WDS clients used (Dual stack
contexts), the detach_shutdown path needs to send a Stop Network
command on any client with an ongoing packet connection.

Implement this by keeping track of WDS clients used for ipv4 and ipv6
families respectively and their respective packet handles.  Rename
member 'wds' to 'ipv4', it is used as-is for currently existing code
paths.  Similarly, rename pkt_handle to packet_handle_ipv4.

Note that the dedicated WDS client associated with the 'ipv6'
qmi_service handle is effectively not used as of this commit.  This is
because packet_handle_ipv6 is never set.  IPv6-only context activations
will continue using 'ipv4' and 'packet_handle_ipv4'.  This will be
addressed in follow-on commits.
---
 drivers/qmimodem/gprs-context.c | 114 ++++++++++++++++++++++++++------
 1 file changed, 95 insertions(+), 19 deletions(-)
diff mbox series

Patch

diff --git a/drivers/qmimodem/gprs-context.c b/drivers/qmimodem/gprs-context.c
index 456f46ead6d5..f4846f0299e7 100644
--- a/drivers/qmimodem/gprs-context.c
+++ b/drivers/qmimodem/gprs-context.c
@@ -21,13 +21,26 @@ 
 #include "util.h"
 
 struct gprs_context_data {
-	struct qmi_service *wds;
+	struct qmi_service *ipv4;
 	struct qmi_service *ipv6;
 	unsigned int active_context;
-	uint32_t pkt_handle;
+	uint32_t packet_handle_ipv4;
+	uint32_t packet_handle_ipv6;
 	uint8_t mux_id;
 };
 
+static void check_all_deactivated(struct ofono_gprs_context *gc)
+{
+	struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+
+	if (data->packet_handle_ipv4 || data->packet_handle_ipv6)
+		return;
+
+	/* All families have been disconnected */
+	ofono_gprs_context_deactivated(gc, data->active_context);
+	data->active_context = 0;
+}
+
 static void pkt_status_notify(struct qmi_result *result, void *user_data)
 {
 	static const uint8_t RESULT_CONN_STATUS = 0x01;
@@ -54,12 +67,11 @@  static void pkt_status_notify(struct qmi_result *result, void *user_data)
 
 	switch (status->status) {
 	case QMI_WDS_CONNECTION_STATUS_DISCONNECTED:
-		if (data->pkt_handle) {
-			/* The context has been disconnected by the network */
-			ofono_gprs_context_deactivated(gc, data->active_context);
-			data->pkt_handle = 0;
-			data->active_context = 0;
+		if (data->packet_handle_ipv4) {
+			data->packet_handle_ipv4 = 0;
+			check_all_deactivated(gc);
 		}
+
 		break;
 	}
 }
@@ -227,7 +239,7 @@  static void start_net_cb(struct qmi_result *result, void *user_data)
 
 	DBG("packet handle %d", handle);
 
-	data->pkt_handle = handle;
+	data->packet_handle_ipv4 = handle;
 
 	/*
 	 * Explicitly request certain information to be provided.  The requested
@@ -243,7 +255,7 @@  static void start_net_cb(struct qmi_result *result, void *user_data)
 	param = qmi_param_new_uint32(PARAM_REQUESTED_SETTINGS,
 						requested_settings);
 
-	if (qmi_service_send(data->wds, QMI_WDS_GET_CURRENT_SETTINGS, param,
+	if (qmi_service_send(data->ipv4, QMI_WDS_GET_CURRENT_SETTINGS, param,
 				get_settings_cb, cbd, cb_data_unref) > 0) {
 		cb_data_ref(cbd);
 		return;
@@ -292,7 +304,7 @@  static void get_lte_attach_param_cb(struct qmi_result *result, void *user_data)
 
 	param = qmi_param_new_uint8(QMI_WDS_PARAM_IP_FAMILY, ip_family);
 
-	if (qmi_service_send(data->wds, QMI_WDS_START_NETWORK, param,
+	if (qmi_service_send(data->ipv4, QMI_WDS_START_NETWORK, param,
 					start_net_cb, cbd, cb_data_unref) > 0) {
 		cb_data_ref(cbd);
 		return;
@@ -322,7 +334,7 @@  static void qmi_gprs_read_settings(struct ofono_gprs_context* gc,
 
 	DBG("cid %u", cid);
 
-	if (qmi_service_send(data->wds, QMI_WDS_GET_LTE_ATTACH_PARAMETERS,
+	if (qmi_service_send(data->ipv4, QMI_WDS_GET_LTE_ATTACH_PARAMETERS,
 				NULL, get_lte_attach_param_cb, cbd,
 				cb_data_unref) > 0) {
 		data->active_context = cid;
@@ -381,7 +393,7 @@  static void qmi_activate_primary(struct ofono_gprs_context *gc,
 		qmi_param_append(param, QMI_WDS_PARAM_PASSWORD,
 					strlen(ctx->password), ctx->password);
 
-	if (qmi_service_send(data->wds, QMI_WDS_START_NETWORK, param,
+	if (qmi_service_send(data->ipv4, QMI_WDS_START_NETWORK, param,
 					start_net_cb, cbd, cb_data_unref) > 0)
 		return;
 
@@ -395,6 +407,24 @@  error:
 	l_free(cbd);
 }
 
+static uint32_t send_stop_net(struct qmi_service *wds, uint32_t packet_handle,
+				qmi_service_result_func_t func,
+				void *user_data, qmi_destroy_func_t destroy)
+{
+	static const uint8_t PARAM_PACKET_HANDLE = 0x01;
+	struct qmi_param *param = qmi_param_new_uint32(PARAM_PACKET_HANDLE,
+							packet_handle);
+	uint32_t id;
+
+	id = qmi_service_send(wds, QMI_WDS_STOP_NETWORK, param,
+				func, user_data, destroy);
+
+	if (!id)
+		qmi_param_free(param);
+
+	return id;
+}
+
 static void stop_net_cb(struct qmi_result *result, void *user_data)
 {
 	struct cb_data *cbd = user_data;
@@ -410,7 +440,7 @@  static void stop_net_cb(struct qmi_result *result, void *user_data)
 		return;
 	}
 
-	data->pkt_handle = 0;
+	data->packet_handle_ipv4 = 0;
 
 	if (cb)
 		CALLBACK_WITH_SUCCESS(cb, cbd->data);
@@ -433,9 +463,10 @@  static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
 
 	cbd->user = gc;
 
-	param = qmi_param_new_uint32(PARAM_PACKET_HANDLE, data->pkt_handle);
+	param = qmi_param_new_uint32(PARAM_PACKET_HANDLE,
+						data->packet_handle_ipv4);
 
-	if (qmi_service_send(data->wds, QMI_WDS_STOP_NETWORK, param,
+	if (qmi_service_send(data->ipv4, QMI_WDS_STOP_NETWORK, param,
 					stop_net_cb, cbd, l_free) > 0)
 		return;
 
@@ -447,12 +478,57 @@  static void qmi_deactivate_primary(struct ofono_gprs_context *gc,
 	l_free(cbd);
 }
 
+static void stop_net_detach_ipv4_cb(struct qmi_result *result, void *user_data)
+{
+	struct ofono_gprs_context *gc = user_data;
+	struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+	uint16_t error;
+
+	if (!qmi_result_set_error(result, &error))
+		error = 0;
+
+	DBG("error: %u", error);
+
+	data->packet_handle_ipv4 = 0;
+	check_all_deactivated(gc);
+}
+
+static void stop_net_detach_ipv6_cb(struct qmi_result *result, void *user_data)
+{
+	struct ofono_gprs_context *gc = user_data;
+	struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+	uint16_t error;
+
+	if (!qmi_result_set_error(result, &error))
+		error = 0;
+
+	DBG("error: %u", error);
+
+	data->packet_handle_ipv6 = 0;
+	check_all_deactivated(gc);
+}
+
 static void qmi_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
 						unsigned int cid)
 {
+	struct gprs_context_data *data = ofono_gprs_context_get_data(gc);
+
 	DBG("");
 
-	qmi_deactivate_primary(gc, cid, NULL, NULL);
+	if (data->packet_handle_ipv6 &&
+			!send_stop_net(data->ipv6, data->packet_handle_ipv6,
+					stop_net_detach_ipv6_cb, gc, NULL))
+		data->packet_handle_ipv6 = 0;
+
+	if (data->packet_handle_ipv4 &&
+			!send_stop_net(data->ipv4, data->packet_handle_ipv4,
+					stop_net_detach_ipv4_cb, gc, NULL))
+		data->packet_handle_ipv4 = 0;
+
+	if (data->packet_handle_ipv4 || data->packet_handle_ipv6)
+		return;
+
+	data->active_context = 0;
 }
 
 static void set_ip_family_preference_cb(struct qmi_result *result,
@@ -603,11 +679,11 @@  static int qmi_gprs_context_probev(struct ofono_gprs_context *gc,
 		return r;
 
 	data = l_new(struct gprs_context_data, 1);
-	data->wds = l_steal_ptr(ipv4);
+	data->ipv4 = l_steal_ptr(ipv4);
 	data->ipv6 = l_steal_ptr(ipv6);
 	data->mux_id = mux_id;
 
-	qmi_service_register(data->wds, QMI_WDS_PACKET_SERVICE_STATUS,
+	qmi_service_register(data->ipv4, QMI_WDS_PACKET_SERVICE_STATUS,
 					pkt_status_notify, gc, NULL);
 	qmi_service_register(data->ipv6, QMI_WDS_PACKET_SERVICE_STATUS,
 					pkt_status_notify, gc, NULL);
@@ -625,7 +701,7 @@  static void qmi_gprs_context_remove(struct ofono_gprs_context *gc)
 
 	ofono_gprs_context_set_data(gc, NULL);
 
-	qmi_service_free(data->wds);
+	qmi_service_free(data->ipv4);
 	qmi_service_free(data->ipv6);
 	l_free(data);
 }