diff mbox series

[8/8] rmnet: Implement cancel

Message ID 20241115220053.49613-8-denkenz@gmail.com (mailing list archive)
State Superseded
Headers show
Series [1/8] rmnet: Add skeleton | expand

Commit Message

Denis Kenzior Nov. 15, 2024, 10 p.m. UTC
Implement cancelation of an ongoing rmnet request.  Any links that have
already been created are deleted by putting another request to the head
of the queue.
---
 src/rmnet.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 67 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/src/rmnet.c b/src/rmnet.c
index 4a921b330b72..07dada9178ad 100644
--- a/src/rmnet.c
+++ b/src/rmnet.c
@@ -32,6 +32,7 @@  struct rmnet_request {
 	void *user_data;
 	rmnet_destroy_func_t destroy;
 	int id;
+	bool canceled;
 	uint32_t netlink_id;
 	uint16_t request_type;
 	uint8_t current;
@@ -54,6 +55,14 @@  static void rmnet_request_free(struct rmnet_request *req)
 	l_free(req);
 }
 
+static bool rmnet_request_id_matches(const void *a, const void *b)
+{
+	const struct rmnet_request *req = a;
+	int id = L_PTR_TO_INT(b);
+
+	return req->id == id;
+}
+
 static struct rmnet_request *__rmnet_del_request_new(unsigned int n_interfaces,
 					const struct rmnet_ifinfo *interfaces)
 {
@@ -185,7 +194,7 @@  static void rmnet_new_link_cb(int error, uint16_t type, const void *data,
 	if (!error)
 		req->current += 1;
 
-	if (error) {
+	if (error || req->canceled) {
 		if (req->current > 0) {
 			struct rmnet_request *del_req =
 				__rmnet_del_request_new(req->current,
@@ -268,6 +277,7 @@  int rmnet_get_interfaces(uint32_t parent_ifindex, unsigned int n_interfaces,
 	req->user_data = user_data;
 	req->destroy = destroy;
 	req->id = next_request_id++;
+	req->canceled = false;
 	req->request_type = RTM_NEWLINK;
 	req->netlink_id = 0;
 	req->current = 0;
@@ -304,7 +314,62 @@  int rmnet_del_interfaces(unsigned int n_interfaces,
 
 int rmnet_cancel(int id)
 {
-	return -ENOTSUP;
+	struct rmnet_request *req;
+
+	req = l_queue_peek_head(request_q);
+	if (!req)
+		return -ENOENT;
+
+	/* Simple Case: Request not yet started (not queue head) */
+	if (req->id != id) {
+		req = l_queue_remove_if(request_q, rmnet_request_id_matches,
+						L_INT_TO_PTR(id));
+		if (!req)
+			return -ENOENT;
+
+		DBG("Removing non-head of queue request %u", id);
+		rmnet_request_free(req);
+		return 0;
+	}
+
+	/* Harder Case: In progress, but the next request not in flight */
+	if (!l_netlink_request_sent(rtnl, req->netlink_id)) {
+		DBG("Removing in-progress request (not in flight) %u", id);
+		req = l_queue_pop_head(request_q);
+		l_netlink_cancel(rtnl, req->netlink_id);
+
+		if (req->current > 0) {
+			struct rmnet_request *del_req =
+				__rmnet_del_request_new(req->current,
+								req->infos);
+
+			l_queue_push_head(request_q, del_req);
+		}
+
+		rmnet_request_free(req);
+
+		if (l_queue_length(request_q))
+			rmnet_start_next_request();
+
+		return 0;
+	}
+
+	/*
+	 * Hardest Case: In progress, next request in flight
+	 * We have to wait until the next callback since the ifindex won't be
+	 * known until then.
+	 */
+	if (req->destroy)
+		req->destroy(req->user_data);
+
+	req->new_cb = NULL;
+	req->destroy = NULL;
+	req->user_data = NULL;
+
+	DBG("Setting canceled on in-progress request %u", id);
+	req->canceled = true;
+
+	return 0;
 }
 
 static int rmnet_parse_info_data(struct l_netlink_attr *linkinfo,