Re: [PATCH] connman : Introduce softap with ip feature to connman

Michael Nazzareno Trimarchi <[email protected]> Mon, 2 Jun 2025 09:40:53 +0200
Newsgroups dev.linux.lists.connman
Message-ID <CAOf5uwnBz5gC8+u2PBJAmqa0NnBkww_oG41O=91K4zbcTuTUkg@mail.gmail.com>
Hi

On Mon, Jun 2, 2025 at 8:33 AM Shailesh Rathod/LGSI GPOS Dev
<[email protected]> wrote:
>
> From: Shailesh Rathod<[email protected]>
> Date: Mon, 21 Apr 2025 18:16:09 +0900
>
> 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.
>
> Signed-off-by: Shailesh Rathod<[email protected]>
> ---
>  src/connman.h    |  15 ++++++
>  src/technology.c | 122 +++++++++++++++++++++++++++++++++++++++---
>  src/tethering.c  | 136 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 267 insertions(+), 6 deletions(-)
>
> diff --git a/src/connman.h b/src/connman.h
> index 32ba559..4241a58 100644
> --- a/src/connman.h
> +++ b/src/connman.h
> @@ -676,9 +676,24 @@ 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];
> +};
> +
> +

Can you drop this extra blank line?

Anyway how is different from the one sent by Roman some time ago?

Michael


>  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..719c680 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,18 +237,25 @@ 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;
>
> -       if (enabled) {
> -               err = __connman_tethering_set_enabled();
> -               if (err < 0)
> -                       return err;
> -       } else
> -               __connman_tethering_set_disabled();
> +       ip = technology->tethering_ipaddress;
> +
> +    if (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
> +        __connman_tethering_set_disabled();
>
>         technology->tethering = enabled;
>         tethering_changed(technology);
> @@ -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,55 @@ 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 +1351,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 +2030,18 @@ 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..7039037 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
>
> @@ -200,6 +201,7 @@ static void unregister_all_clients(void)
>         g_hash_table_foreach(clients_table, unregister_client, NULL);
>  }
>
> +
>  int __connman_tethering_set_enabled(void)
>  {
>         int index;
> @@ -363,6 +365,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)
>  {
>
>


--
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
[email protected]
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
[email protected]
www.amarulasolutions.com