Re: [PATCH] connman : Introduce softap with ip feature to connman
Shailesh Rathod/LGSI Connectivity Team <[email protected]> Fri, 11 Jul 2025 11:13:36 +0000
| Newsgroups | dev.linux.lists.connman |
|---|---|
| Message-ID | <SE1P216MB2647C232928EFD6B3B54BCA8F04BA@SE1P216MB2647.KORP216.PROD.OUTLOOK.COM> |
Hello Michael, Sorry for the delayed response. I dont think roman patch handles the channel settings and other ip checks (ex. __connman_tethering_set_enabled_with_ip function impl) Let me know your thoughts on our implementation. Please find the corrected patch. From 84d64870ddecede4fe687eb1cafcbb4fac87a990 Mon Sep 17 00:00:00 2001 From: "jisoo.cha" <[email protected]> Date: Mon, 21 Apr 2025 18:16:09 +0900 Subject: [PATCH] Introduce softap with ip feature to connman By default, ConnMan supports tethering with a passphrase. However, it does not support configuring tethering with a specific IP address and channel.For certain applications it is essential to set a specific IP address for the SoftAP. To enable support for specifying the IP address and channel, new properties TetheringIPAddress and TetheringChannel should be added. --- src/connman.h | 13 +++++ src/technology.c | 109 +++++++++++++++++++++++++++++++++++++- src/tethering.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+), 1 deletion(-) diff --git a/src/connman.h b/src/connman.h index 7ebda7a..85f221e 100644 --- a/src/connman.h +++ b/src/connman.h @@ -677,9 +677,22 @@ bool __connman_config_address_provisioned(const char *address, #include <connman/tethering.h> +struct connman_station_info { + bool is_connected; + char *path; + char *type; + char ip[64]; + char mac[32]; + char hostname[64]; +}; + int __connman_tethering_init(void); void __connman_tethering_cleanup(void); +GHashTable *__connman_tethering_get_sta_hash(); + +void __connman_tethering_list_clients(DBusMessageIter *array); +int __connman_tethering_set_enabled_with_ip(const char *ip); const char *__connman_tethering_get_bridge(void); int __connman_tethering_set_enabled(void); void __connman_tethering_set_disabled(void); diff --git a/src/technology.c b/src/technology.c index 270d83d..51f3cf0 100644 --- a/src/technology.c +++ b/src/technology.c @@ -69,6 +69,8 @@ struct connman_technology { char *tethering_ident; char *tethering_passphrase; int tethering_freq; + char *tethering_ipaddress; + unsigned int tethering_channel; bool enable_persistent; /* Save the tech state */ @@ -195,6 +197,16 @@ static void technology_save(struct connman_technology *technology) g_free(enc); } + if (technology->tethering_channel) + g_key_file_set_integer(keyfile, identifier, + "Tethering.Channel", + technology->tethering_channel); + + if (technology->tethering_ipaddress) + g_key_file_set_string(keyfile, identifier, + "Tethering.IP", + technology->tethering_ipaddress); + if (technology->tethering_freq == 0) technology->tethering_freq = 2412; @@ -225,14 +237,21 @@ int connman_technology_tethering_notify(struct connman_technology *technology, bool enabled) { int err; + const char *ip; DBG("technology %p enabled %u", technology, enabled); if (technology->tethering == enabled) return -EALREADY; + ip = technology->tethering_ipaddress; + if (enabled) { - err = __connman_tethering_set_enabled(); + if (!ip || strlen(ip) == 0) + err = __connman_tethering_set_enabled(); + else + err = __connman_tethering_set_enabled_with_ip(ip); + if (err < 0) return err; } else @@ -417,6 +436,17 @@ bool connman_technology_get_wifi_tethering(const struct connman_technology *tech return true; } +unsigned int connman_technology_get_wifi_tethering_channel(void) +{ + struct connman_technology *technology; + + technology = technology_find(CONNMAN_SERVICE_TYPE_WIFI); + if (!technology) + return 0; + + return technology->tethering_channel; +} + static void free_rfkill(gpointer data) { struct connman_rfkill *rfkill = data; @@ -479,6 +509,12 @@ static void technology_load(struct connman_technology *technology) enc = g_key_file_get_string(keyfile, identifier, "Tethering.Passphrase", NULL); + + technology->tethering_channel = g_key_file_get_integer(keyfile, + identifier, "Tethering.Channel", NULL); + + technology->tethering_ipaddress = g_key_file_get_string(keyfile, + identifier, "Tethering.IP", NULL); if (enc) { technology->tethering_passphrase = g_strcompress(enc); g_free(enc); @@ -597,6 +633,15 @@ static void append_properties(DBusMessageIter *iter, connman_dbus_dict_append_basic(&dict, "TetheringPassphrase", DBUS_TYPE_STRING, &technology->tethering_passphrase); + if (technology->tethering_ipaddress) + connman_dbus_dict_append_basic(&dict, "TetheringIPAddress", + DBUS_TYPE_STRING, + &technology->tethering_ipaddress); + + if (technology->tethering_channel) + connman_dbus_dict_append_basic(&dict, "TetheringChannel", + DBUS_TYPE_UINT32, + &technology->tethering_channel); connman_dbus_dict_append_basic(&dict, "TetheringFreq", DBUS_TYPE_INT32, @@ -1016,6 +1061,54 @@ static DBusMessage *set_property(DBusConnection *conn, DBUS_TYPE_STRING, &technology->tethering_passphrase); } + } else if (g_str_equal(name, "TetheringChannel")) { + dbus_uint32_t channel; + + if (type != DBUS_TYPE_UINT32) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value, &channel); + + if (technology->type != CONNMAN_SERVICE_TYPE_WIFI) + return __connman_error_not_supported(msg); + + if (channel == 0 || channel > 13) + return __connman_error_invalid_arguments(msg); + + if (technology->tethering_channel != channel) { + technology->tethering_channel = channel; + technology_save(technology); + + connman_dbus_property_changed_basic(technology->path, + CONNMAN_TECHNOLOGY_INTERFACE, + "TetheringChannel", + DBUS_TYPE_UINT32, + &technology->tethering_channel); + } + } else if (g_str_equal(name, "TetheringIPAddress")) { + const char *str = NULL; + + dbus_message_iter_get_basic(&value, &str); + + if (technology->type != CONNMAN_SERVICE_TYPE_WIFI) + return __connman_error_not_supported(msg); + + if (!str || strlen(str) == 0) { + g_free(technology->tethering_ipaddress); + technology->tethering_ipaddress = NULL; + return __connman_error_invalid_arguments(msg); + } + if (g_strcmp0(technology->tethering_ipaddress, str) != 0) { + g_free(technology->tethering_ipaddress); + technology->tethering_ipaddress = g_strdup(str); + technology_save(technology); + + connman_dbus_property_changed_basic(technology->path, + CONNMAN_TECHNOLOGY_INTERFACE, + "TetheringIPAddress", + DBUS_TYPE_STRING, + &technology->tethering_ipaddress); + } } else if (g_str_equal(name, "TetheringFreq")) { dbus_int32_t freq; @@ -1257,6 +1350,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_ipaddress); g_free(technology); } @@ -1935,3 +2029,16 @@ void __connman_technology_cleanup(void) g_free(global_regdom); } + +void __connman_technology_sta_count_changed(enum connman_service_type type, int stacount) +{ + struct connman_technology *technology; + + technology = technology_find(type); + if (technology == NULL) + return; + + connman_dbus_property_changed_basic(technology->path, + CONNMAN_TECHNOLOGY_INTERFACE, "StaCount", + DBUS_TYPE_INT32, &stacount); +} \ No newline at end of file diff --git a/src/tethering.c b/src/tethering.c index f930a26..2e1e6a4 100644 --- a/src/tethering.c +++ b/src/tethering.c @@ -49,6 +49,7 @@ #endif #define BRIDGE_NAME "tether" +#define SUBNET_MASK_24 "255.255.255.0" #define DEFAULT_MTU 1500 @@ -363,6 +364,140 @@ void __connman_tethering_list_clients(DBusMessageIter *array) g_hash_table_foreach(clients_table, append_client, array); } +static char *get_ip(uint32_t ip) +{ + struct in_addr addr; + + addr.s_addr = htonl(ip); + + return g_strdup(inet_ntoa(addr)); +} + +int __connman_tethering_set_enabled_with_ip(const char *ip) +{ + int index; + int err; + const char *gateway; + const char *broadcast; + const char *subnet_mask; + const char *start_ip; + const char *end_ip; + const char *dns; + unsigned char prefixlen; + char **ns; + + DBG("enabled %d", tethering_enabled + 1); + + if (__sync_fetch_and_add(&tethering_enabled, 1) != 0) + return 0; + + err = __connman_bridge_create(BRIDGE_NAME); + if (err < 0) { + __sync_fetch_and_sub(&tethering_enabled, 1); + return 0; + } + + index = connman_inet_ifindex(BRIDGE_NAME); + + __connman_ippool_newaddr(index, ip, 24); + + struct in_addr inp; + uint32_t start, mask; + + if (inet_aton(ip, &inp) == 0) + return 0; + + start = ntohl(inp.s_addr); + mask = ~(0xffffffff >> 24); + + start = start & mask; + + gateway = ip; + broadcast = get_ip(start + 255); + subnet_mask = SUBNET_MASK_24; + start_ip = get_ip(start + 2); + end_ip = get_ip(start + 254); + + err = __connman_bridge_enable(BRIDGE_NAME, gateway, + connman_ipaddress_calc_netmask_len(subnet_mask), + broadcast); + if (err < 0 && err != -EALREADY) { + __connman_ippool_free(dhcp_ippool); + __connman_ippool_deladdr(index, ip, 24); + __connman_bridge_remove(BRIDGE_NAME); + __sync_fetch_and_sub(&tethering_enabled, 1); + err = -EADDRNOTAVAIL; + goto clean; + } + + ns = connman_setting_get_string_list("FallbackNameservers"); + if (ns) { + if (ns[0]) { + g_free(private_network_primary_dns); + private_network_primary_dns = g_strdup(ns[0]); + } + if (ns[1]) { + g_free(private_network_secondary_dns); + private_network_secondary_dns = g_strdup(ns[1]); + } + + DBG("Fallback ns primary %s secondary %s", + private_network_primary_dns, + private_network_secondary_dns); + } + + dns = gateway; + if (__connman_dnsproxy_add_listener(index) < 0) { + connman_error("Can't add listener %s to DNS proxy", + BRIDGE_NAME); + dns = private_network_primary_dns; + DBG("Serving %s nameserver to clients", dns); + } + + tethering_dhcp_server = dhcp_server_start(BRIDGE_NAME, + gateway, subnet_mask, + start_ip, end_ip, + 24 * 3600, dns); + if (!tethering_dhcp_server) { + __connman_bridge_disable(BRIDGE_NAME); + __connman_ippool_free(dhcp_ippool); + __connman_ippool_deladdr(index, ip, 24); + __connman_bridge_remove(BRIDGE_NAME); + __sync_fetch_and_sub(&tethering_enabled, 1); + err = -EOPNOTSUPP; + goto clean; + } + + prefixlen = connman_ipaddress_calc_netmask_len(subnet_mask); + err = __connman_nat_enable(BRIDGE_NAME, start_ip, prefixlen); + if (err < 0) { + connman_error("Cannot enable NAT %d/%s", err, strerror(-err)); + dhcp_server_stop(tethering_dhcp_server); + __connman_bridge_disable(BRIDGE_NAME); + __connman_ippool_free(dhcp_ippool); + __connman_ippool_deladdr(index, ip, 24); + __connman_bridge_remove(BRIDGE_NAME); + __sync_fetch_and_sub(&tethering_enabled, 1); + err = -EOPNOTSUPP; + goto clean; + } + + err = __connman_ipv6pd_setup(BRIDGE_NAME); + if (err < 0 && err != -EINPROGRESS) + DBG("Cannot setup IPv6 prefix delegation %d/%s", err, + strerror(-err)); +clean: + g_free(broadcast); + g_free(start_ip); + g_free(end_ip); + if ((err == -EOPNOTSUPP) || (err == -EADDRNOTAVAIL)){ + return err; + } else { + DBG("tethering started"); + return 0; + } +} + static void setup_tun_interface(unsigned int flags, unsigned change, void *data) {