ConnMan network manager
 help / color / mirror / Atom feed
From: Miroslav Cuvar <miroslav.cuvar@kistler.com>
To: <connman@lists.linux.dev>
Cc: Miroslav Cuvar <miroslav.cuvar@kistler.com>
Subject: [PATCH 1/1] Added support for setting preferred IP for WiFi tethering
Date: Tue, 8 Nov 2022 08:18:20 +0100	[thread overview]
Message-ID: <20221108071820.14101-1-miroslav.cuvar@kistler.com> (raw)

Hello,

This patch is to enable the user to set a preferred IP when enabling WiFi tethering, if the preferred IP is not available, the closest next available IP will be used.
The preferred IP is set using DBus and it works by explicitly setting the starting block in static uint32_t get_free_block(unsigned int);
Would a feature like this benefit the connman project?

Signed-off-by: Miroslav Cuvar <miroslav.cuvar@kistler.com>
---
 doc/technology-api.txt |  8 ++++++++
 src/connman.h          |  6 +++++-
 src/ippool.c           | 19 +++++++++++-------
 src/peer.c             |  2 +-
 src/technology.c       | 45 ++++++++++++++++++++++++++++++++++++++++++
 src/tethering.c        | 11 +++++++++--
 unit/test-ippool.c     | 20 +++++++++----------
 7 files changed, 90 insertions(+), 21 deletions(-)

diff --git a/doc/technology-api.txt b/doc/technology-api.txt
index cdf30396..4492a7f6 100644
--- a/doc/technology-api.txt
+++ b/doc/technology-api.txt
@@ -107,3 +107,11 @@ Properties	boolean Powered [readwrite]
 
 			This property is only valid for the WiFi technology and it's
 			optional. Default frequency is 2412 Mhz.
+
+		int TetheringPreferredIP [readwrite]
+
+			Preferred start IP for WiFi tethering IP pool. If the IP is not
+			free, closest next free IP will be chosen.
+
+			This property is only valid for the WiFi technology and it's
+			optional. Default value is 0, which means no preference for IP. 
diff --git a/src/connman.h b/src/connman.h
index b955d98b..d4aaf7a0 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -649,6 +649,7 @@ const char *__connman_tethering_get_bridge(void);
 int __connman_tethering_set_enabled(void);
 void __connman_tethering_set_disabled(void);
 void __connman_tethering_list_clients(DBusMessageIter *array);
+void __connman_tethering_set_preferred_ip(uint32_t preferred_ip);
 
 int __connman_private_network_request(DBusMessage *msg, const char *owner);
 int __connman_private_network_release(const char *path);
@@ -1007,7 +1008,8 @@ struct connman_ippool *__connman_ippool_create(int index,
 					unsigned int start,
 					unsigned int range,
 					ippool_collision_cb_t collision_cb,
-					void *user_data);
+					void *user_data,
+					uint32_t preferred_ip);
 
 const char *__connman_ippool_get_gateway(struct connman_ippool *pool);
 const char *__connman_ippool_get_broadcast(struct connman_ippool *pool);
@@ -1020,6 +1022,8 @@ void __connman_ippool_newaddr(int index, const char *address,
 void __connman_ippool_deladdr(int index, const char *address,
 				unsigned char prefixlen);
 
+bool __connman_ippool_is_private_address(uint32_t address);
+
 int __connman_bridge_create(const char *name);
 int __connman_bridge_remove(const char *name);
 int __connman_bridge_enable(const char *name, const char *ip_address,
diff --git a/src/ippool.c b/src/ippool.c
index f2e9b000..3be47d95 100644
--- a/src/ippool.c
+++ b/src/ippool.c
@@ -152,7 +152,7 @@ static uint32_t next_block(uint32_t block)
 	return (block & 0xffff0000) | ((next << 8) & 0x0000ff00);
 }
 
-static uint32_t get_free_block(unsigned int size)
+static uint32_t get_free_block(unsigned int size, uint32_t preferred_ip)
 {
 	struct address_info *info;
 	uint32_t block;
@@ -160,6 +160,8 @@ static uint32_t get_free_block(unsigned int size)
 	bool collision;
 
 	/*
+	 * If the preferred_ip is specified we try to use that IP or the
+	 * closest next free IP.
 	 * Instead starting always from the 16 bit block, we start
 	 * from the last assigned block. This is a simple optimimazion
 	 * for the case where a lot of blocks have been assigned, e.g.
@@ -169,7 +171,9 @@ static uint32_t get_free_block(unsigned int size)
 	 * To only thing we have to make sure is that we terminated if
 	 * there is no block left.
 	 */
-	if (last_block)
+	if (preferred_ip != 0)
+       		block = preferred_ip;
+    	else if (last_block)
 		block = last_block;
 	else
 		block = block_16_bits;
@@ -208,7 +212,7 @@ static struct address_info *lookup_info(int index, uint32_t start)
 	return NULL;
 }
 
-static bool is_private_address(uint32_t address)
+bool __connman_ippool_is_private_address(uint32_t address)
 {
 	unsigned int a, b;
 
@@ -234,7 +238,7 @@ void __connman_ippool_newaddr(int index, const char *address,
 		return;
 
 	start = ntohl(inp.s_addr);
-	if (!is_private_address(start))
+	if (!__connman_ippool_is_private_address(start))
 		return;
 
 	if (prefixlen >= 32)
@@ -297,7 +301,7 @@ void __connman_ippool_deladdr(int index, const char *address,
 		return;
 
 	start = ntohl(inp.s_addr);
-	if (!is_private_address(start))
+	if (!__connman_ippool_is_private_address(start))
 		return;
 
 	mask = ~(0xffffffff >> prefixlen);
@@ -325,7 +329,8 @@ struct connman_ippool *__connman_ippool_create(int index,
 					unsigned int start,
 					unsigned int range,
 					ippool_collision_cb_t collision_cb,
-					void *user_data)
+					void *user_data,
+					uint32_t preferred_ip)
 {
 	struct connman_ippool *pool;
 	struct address_info *info;
@@ -342,7 +347,7 @@ struct connman_ippool *__connman_ippool_create(int index,
 		return NULL;
 	}
 
-	block = get_free_block(start + range);
+	block = get_free_block(start + range, preferred_ip);
 	if (block == 0) {
 		connman_warn("Could not find a free IP block");
 		return NULL;
diff --git a/src/peer.c b/src/peer.c
index bad5c841..5406da37 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -140,7 +140,7 @@ static int start_dhcp_server(struct connman_peer *peer)
 	else
 		index = connman_device_get_index(peer->device);
 
-	peer->ip_pool = __connman_ippool_create(index, 2, 1, NULL, NULL);
+	peer->ip_pool = __connman_ippool_create(index, 2, 1, NULL, NULL, 0);
 	if (!peer->ip_pool)
 		goto error;
 
diff --git a/src/technology.c b/src/technology.c
index 5c469111..ff085ec2 100644
--- a/src/technology.c
+++ b/src/technology.c
@@ -67,6 +67,10 @@ struct connman_technology {
 	char *tethering_ident;
 	char *tethering_passphrase;
 	int tethering_freq;
+	char *tethering_preferred_ip; /* WIFI specific, used as first IP
+				       * when searching for free block when
+				       * starting tethering.
+				       */
 
 	bool enable_persistent; /* Save the tech state */
 
@@ -175,6 +179,12 @@ static void technology_save(struct connman_technology *technology)
 	if (!identifier)
 		goto done;
 
+	if (technology->tethering_preferred_ip){
+		g_key_file_set_string(keyfile, identifier,
+		"Tethering.PreferredIP",
+		technology->tethering_preferred_ip);
+	}
+
 	g_key_file_set_boolean(keyfile, identifier, "Enable",
 				technology->enable_persistent);
 
@@ -229,6 +239,9 @@ int connman_technology_tethering_notify(struct connman_technology *technology,
 	if (technology->tethering == enabled)
 		return -EALREADY;
 
+	if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && technology->tethering_preferred_ip != NULL)
+		__connman_tethering_set_preferred_ip(ntohl(inet_addr(technology->tethering_preferred_ip)));
+
 	if (enabled) {
 		err = __connman_tethering_set_enabled();
 		if (err < 0)
@@ -461,6 +474,9 @@ static void technology_load(struct connman_technology *technology)
 	technology->tethering_freq = g_key_file_get_integer(keyfile,
 				identifier, "Tethering.Freq", NULL);
 
+	technology->tethering_preferred_ip = g_key_file_get_string(keyfile,
+			identifier, "Tethering.PreferredIP", NULL);
+
 done:
 	g_free(identifier);
 
@@ -576,6 +592,11 @@ static void append_properties(DBusMessageIter *iter,
 				DBUS_TYPE_INT32,
 				&technology->tethering_freq);
 
+	if (technology->tethering_preferred_ip)
+		connman_dbus_dict_append_basic(&dict, "TetheringPreferredIP",
+		DBUS_TYPE_STRING,
+		&technology->tethering_preferred_ip);
+
 	connman_dbus_dict_close(iter, &dict);
 }
 
@@ -1011,6 +1032,29 @@ static DBusMessage *set_property(DBusConnection *conn,
 					DBUS_TYPE_INT32,
 					&technology->tethering_freq);
 		}
+	} else if (g_str_equal(name, "TetheringPreferredIP")) {
+		const char *str;
+
+		dbus_message_iter_get_basic(&value, &str);
+		if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
+			return __connman_error_not_supported(msg);
+
+		uint32_t preferred_ip	= ntohl(inet_addr(str));
+		if (preferred_ip != 0 && !__connman_ippool_is_private_address(preferred_ip)) {
+			return __connman_error_invalid_arguments(msg);
+		}
+ 
+		if (g_strcmp0(technology->tethering_preferred_ip, str) != 0) {
+			g_free(technology->tethering_preferred_ip);
+			technology->tethering_preferred_ip = g_strdup(str);
+			technology_save(technology);
+
+			connman_dbus_property_changed_basic(technology->path,
+				CONNMAN_TECHNOLOGY_INTERFACE,
+				"TetheringPreferredIP",
+				DBUS_TYPE_STRING,
+				&technology->tethering_preferred_ip);
+		}
 	} else if (g_str_equal(name, "Powered")) {
 		dbus_bool_t enable;
 
@@ -1231,6 +1275,7 @@ static void technology_put(struct connman_technology *technology)
 	g_free(technology->regdom);
 	g_free(technology->tethering_ident);
 	g_free(technology->tethering_passphrase);
+	g_free(technology->tethering_preferred_ip);
 	g_free(technology);
 }
 
diff --git a/src/tethering.c b/src/tethering.c
index f930a26b..05958ddd 100644
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -63,6 +63,8 @@ static GHashTable *pn_hash;
 
 static GHashTable *clients_table;
 
+static uint32_t tethering_preferred_ip = 0;
+
 struct _clients_notify {
 	int id;
 	GHashTable *remove;
@@ -226,7 +228,7 @@ int __connman_tethering_set_enabled(void)
 
 	index = connman_inet_ifindex(BRIDGE_NAME);
 	dhcp_ippool = __connman_ippool_create(index, 2, 252,
-						tethering_restart, NULL);
+						tethering_restart, NULL, tethering_preferred_ip);
 	if (!dhcp_ippool) {
 		connman_error("Fail to create IP pool");
 		__connman_bridge_remove(BRIDGE_NAME);
@@ -592,7 +594,7 @@ int __connman_private_network_request(DBusMessage *msg, const char *owner)
 	pn->fd = fd;
 	pn->interface = iface;
 	pn->index = index;
-	pn->pool = __connman_ippool_create(pn->index, 1, 1, ippool_disconnect, pn);
+	pn->pool = __connman_ippool_create(pn->index, 1, 1, ippool_disconnect, pn, 0);
 	if (!pn->pool) {
 		errno = -ENOMEM;
 		goto error;
@@ -691,3 +693,8 @@ void __connman_tethering_cleanup(void)
 
 	dbus_connection_unref(connection);
 }
+
+void __connman_tethering_set_preferred_ip(uint32_t preferred_ip){
+    DBG("Setting prefered IP: %d", preferred_ip);
+    tethering_preferred_ip = preferred_ip;
+}
diff --git a/unit/test-ippool.c b/unit/test-ippool.c
index a6cae652..ec4727c2 100644
--- a/unit/test-ippool.c
+++ b/unit/test-ippool.c
@@ -46,11 +46,11 @@ static void test_case_1(void)
 
 	__connman_ippool_init();
 
-	pool = __connman_ippool_create(23, 1, 500, NULL, NULL);
+	pool = __connman_ippool_create(23, 1, 500, NULL, NULL, 0);
 	g_assert(!pool);
 
 	for (i = 0; i < 100000; i++) {
-		pool = __connman_ippool_create(23, 1, 20, NULL, NULL);
+		pool = __connman_ippool_create(23, 1, 20, NULL, NULL, 0);
 		g_assert(pool);
 
 		__connman_ippool_free(pool);
@@ -73,7 +73,7 @@ static void test_case_2(void)
 
 	/* Test the IP range */
 	for (i = 1; i < 254; i++) {
-		pool = __connman_ippool_create(23, 1, i, NULL, NULL);
+		pool = __connman_ippool_create(23, 1, i, NULL, NULL, 0);
 		g_assert(pool);
 
 		gateway = __connman_ippool_get_gateway(pool);
@@ -130,7 +130,7 @@ static void test_case_3(void)
 	__connman_ippool_newaddr(46, "172.16.0.1", 11);
 
 	while (TRUE) {
-		pool = __connman_ippool_create(23, 1, 100, NULL, NULL);
+		pool = __connman_ippool_create(23, 1, 100, NULL, NULL, 0);
 		if (!pool)
 			break;
 		i += 1;
@@ -192,7 +192,7 @@ static void test_case_4(void)
 	/* Test the IP range collision */
 
 	flag = 0;
-	pool = __connman_ippool_create(23, 1, 100, collision_cb, &flag);
+	pool = __connman_ippool_create(23, 1, 100, collision_cb, &flag, 0);
 	g_assert(pool);
 
 	gateway = __connman_ippool_get_gateway(pool);
@@ -223,7 +223,7 @@ static void test_case_4(void)
 
 	flag = 0;
 
-	pool = __connman_ippool_create(23, 1, 100, collision_cb, &flag);
+	pool = __connman_ippool_create(23, 1, 100, collision_cb, &flag, 0);
 	g_assert(pool);
 
 	gateway = __connman_ippool_get_gateway(pool);
@@ -271,7 +271,7 @@ static void test_case_5(void)
 	g_assert(flag == 0);
 
 	/* pool should return 192.168.0.1 now */
-	pool1 = __connman_ippool_create(26, 1, 100, collision_cb, &flag);
+	pool1 = __connman_ippool_create(26, 1, 100, collision_cb, &flag, 0);
 	g_assert(pool1);
 
 	gateway = __connman_ippool_get_gateway(pool1);
@@ -303,7 +303,7 @@ static void test_case_5(void)
 
 	/* pool should return 192.168.2.1 now */
 	flag = 0;
-	pool2 = __connman_ippool_create(23, 1, 100, collision_cb, &flag);
+	pool2 = __connman_ippool_create(23, 1, 100, collision_cb, &flag, 0);
 	g_assert(pool2);
 
 	gateway = __connman_ippool_get_gateway(pool2);
@@ -361,7 +361,7 @@ static void test_case_6(void)
 	g_assert(flag == 0);
 
 	/* pool should return 192.168.2.1 now */
-	pool1 = __connman_ippool_create(26, 1, 100, collision_cb, &flag);
+	pool1 = __connman_ippool_create(26, 1, 100, collision_cb, &flag, 0);
 	g_assert(pool1);
 
 	gateway = __connman_ippool_get_gateway(pool1);
@@ -393,7 +393,7 @@ static void test_case_6(void)
 
 	/* pool should return 192.168.3.1 now */
 	flag = 0;
-	pool2 = __connman_ippool_create(23, 1, 100, collision_cb, &flag);
+	pool2 = __connman_ippool_create(23, 1, 100, collision_cb, &flag, 0);
 	g_assert(pool2);
 
 	gateway = __connman_ippool_get_gateway(pool2);
-- 
2.17.1


Confidentiality Notice: This e-mail is privileged and confidential and for the use of the addressee only. Should you have received this e-mail in error please notify us by replying directly to the sender or by sending a message to info@kistler.com. Unauthorised dissemination, disclosure or copying of the contents of this e-mail, or any similar action, is prohibited. 

             reply	other threads:[~2022-11-08  7:20 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-08  7:18 Miroslav Cuvar [this message]
2023-01-25 11:06 ` [PATCH 1/1] Added support for setting preferred IP for WiFi tethering Miroslav Cuvar
2023-11-07 11:39   ` Cvo
2023-11-08 16:20 ` Denis Kenzior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221108071820.14101-1-miroslav.cuvar@kistler.com \
    --to=miroslav.cuvar@kistler.com \
    --cc=connman@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).