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

Michael Nazzareno Trimarchi <[email protected]> Wed, 13 May 2026 16:59:15 +0200
Newsgroups dev.linux.lists.connman
Message-ID <CAOf5uwkCGjmrBM8SfLnFv6rLj5daUO7Pja2a75_Z48nq-Lzo3A@mail.gmail.com>
Hi all

I will test those patcheset and review it

Michael

On Mon, Jun 2, 2025 at 9:40=E2=80=AFAM Michael Nazzareno Trimarchi
<[email protected]> wrote:
>
> Hi
>
> On Mon, Jun 2, 2025 at 8:33=E2=80=AFAM 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 ch=
ar *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_technol=
ogy *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 =3D=3D 0)
> >                 technology->tethering_freq =3D 2412;
> >
> > @@ -225,18 +237,25 @@ int connman_technology_tethering_notify(struct co=
nnman_technology *technology,
> >                                                         bool enabled)
> >  {
> >         int err;
> > +       const char *ip;
> >
> >         DBG("technology %p enabled %u", technology, enabled);
> >
> >         if (technology->tethering =3D=3D enabled)
> >                 return -EALREADY;
> >
> > -       if (enabled) {
> > -               err =3D __connman_tethering_set_enabled();
> > -               if (err < 0)
> > -                       return err;
> > -       } else
> > -               __connman_tethering_set_disabled();
> > +       ip =3D technology->tethering_ipaddress;
> > +
> > +    if (enabled) {
> > +        if (!ip || strlen(ip) =3D=3D 0)
> > +            err =3D __connman_tethering_set_enabled();
> > +        else
> > +            err =3D __connman_tethering_set_enabled_with_ip(ip);
> > +
> > +        if (err < 0)
> > +            return err;
> > +    } else
> > +        __connman_tethering_set_disabled();
> >
> >         technology->tethering =3D enabled;
> >         tethering_changed(technology);
> > @@ -417,6 +436,17 @@ bool connman_technology_get_wifi_tethering(const s=
truct connman_technology *tech
> >         return true;
> >  }
> >
> > +unsigned int connman_technology_get_wifi_tethering_channel(void)
> > +{
> > +        struct connman_technology *technology;
> > +
> > +        technology =3D technology_find(CONNMAN_SERVICE_TYPE_WIFI);
> > +        if (!technology)
> > +                return 0;
> > +
> > +        return technology->tethering_channel;
> > +}
> > +
> >  static void free_rfkill(gpointer data)
> >  {
> >         struct connman_rfkill *rfkill =3D data;
> > @@ -479,6 +509,12 @@ static void technology_load(struct connman_technol=
ogy *technology)
> >
> >         enc =3D g_key_file_get_string(keyfile,
> >                                 identifier, "Tethering.Passphrase", NUL=
L);
> > +
> > +       technology->tethering_channel =3D g_key_file_get_integer(keyfil=
e,
> > +                identifier, "Tethering.Channel", NULL);
> > +
> > +    technology->tethering_ipaddress =3D g_key_file_get_string(keyfile,
> > +                identifier, "Tethering.IP", NULL);
> >         if (enc) {
> >                 technology->tethering_passphrase =3D g_strcompress(enc)=
;
> >                 g_free(enc);
> > @@ -597,6 +633,15 @@ static void append_properties(DBusMessageIter *ite=
r,
> >                 connman_dbus_dict_append_basic(&dict, "TetheringPassphr=
ase",
> >                                         DBUS_TYPE_STRING,
> >                                         &technology->tethering_passphra=
se);
> > +       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_passphra=
se);
> >                 }
> > +       } else if (g_str_equal(name, "TetheringChannel")) {
> > +                dbus_uint32_t channel;
> > +
> > +                if (type !=3D DBUS_TYPE_UINT32)
> > +                        return __connman_error_invalid_arguments(msg);
> > +
> > +                dbus_message_iter_get_basic(&value, &channel);
> > +
> > +                if (technology->type !=3D CONNMAN_SERVICE_TYPE_WIFI)
> > +                        return __connman_error_not_supported(msg);
> > +
> > +                if (channel =3D=3D 0 || channel > 13)
> > +                        return __connman_error_invalid_arguments(msg);
> > +
> > +                if (technology->tethering_channel !=3D channel) {
> > +
> > +                        technology->tethering_channel =3D 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 =3D NULL;
> > +
> > +                dbus_message_iter_get_basic(&value, &str);
> > +
> > +                if (technology->type !=3D CONNMAN_SERVICE_TYPE_WIFI)
> > +                        return __connman_error_not_supported(msg);
> > +
> > +                if (!str || strlen(str) =3D=3D 0) {
> > +                        g_free(technology->tethering_ipaddress);
> > +                        technology->tethering_ipaddress =3D NULL;
> > +                        return __connman_error_invalid_arguments(msg);
> > +                }
> > +                if (g_strcmp0(technology->tethering_ipaddress, str) !=
=3D 0) {
> > +                        g_free(technology->tethering_ipaddress);
> > +                        technology->tethering_ipaddress =3D g_strdup(s=
tr);
> > +                        technology_save(technology);
> > +
> > +                        connman_dbus_property_changed_basic(technology=
->path,
> > +                                        CONNMAN_TECHNOLOGY_INTERFACE,
> > +                                        "TetheringIPAddress",
> > +                                        DBUS_TYPE_STRING,
> > +                                        &technology->tethering_ipaddre=
ss);
> > +                }
> >         } else if (g_str_equal(name, "TetheringFreq")) {
> >                 dbus_int32_t freq;
> >
> > @@ -1257,6 +1351,7 @@ static void technology_put(struct connman_technol=
ogy *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 =3D technology_find(type);
> > +        if (technology =3D=3D 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(DBusMessage=
Iter *array)
> >         g_hash_table_foreach(clients_table, append_client, array);
> >  }
> >
> > +static char *get_ip(uint32_t ip)
> > +{
> > +        struct in_addr addr;
> > +
> > +        addr.s_addr =3D 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) !=3D 0)
> > +                return 0;
> > +
> > +        err =3D __connman_bridge_create(BRIDGE_NAME);
> > +        if (err < 0) {
> > +                __sync_fetch_and_sub(&tethering_enabled, 1);
> > +                return 0;
> > +        }
> > +
> > +        index =3D connman_inet_ifindex(BRIDGE_NAME);
> > +
> > +        __connman_ippool_newaddr(index, ip, 24);
> > +
> > +        struct in_addr inp;
> > +        uint32_t start, mask;
> > +
> > +        if (inet_aton(ip, &inp) =3D=3D 0)
> > +                return 0;
> > +
> > +        start =3D ntohl(inp.s_addr);
> > +        mask =3D ~(0xffffffff >> 24);
> > +
> > +        start =3D start & mask;
> > +
> > +        gateway =3D ip;
> > +        broadcast =3D get_ip(start + 255);
> > +        subnet_mask =3D SUBNET_MASK_24;
> > +        start_ip =3D get_ip(start + 2);
> > +        end_ip =3D get_ip(start + 254);
> > +
> > +        err =3D __connman_bridge_enable(BRIDGE_NAME, gateway,
> > +                        connman_ipaddress_calc_netmask_len(subnet_mask=
),
> > +                        broadcast);
> > +        if (err < 0 && err !=3D -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 =3D -EADDRNOTAVAIL;
> > +                goto clean;
> > +        }
> > +
> > +        ns =3D connman_setting_get_string_list("FallbackNameservers");
> > +        if (ns) {
> > +                if (ns[0]) {
> > +                        g_free(private_network_primary_dns);
> > +                        private_network_primary_dns =3D g_strdup(ns[0]=
);
> > +                }
> > +                if (ns[1]) {
> > +                        g_free(private_network_secondary_dns);
> > +                        private_network_secondary_dns =3D g_strdup(ns[=
1]);
> > +                }
> > +
> > +                DBG("Fallback ns primary %s secondary %s",
> > +                        private_network_primary_dns,
> > +                        private_network_secondary_dns);
> > +        }
> > +
> > +        dns =3D gateway;
> > +        if (__connman_dnsproxy_add_listener(index) < 0) {
> > +                connman_error("Can't add listener %s to DNS proxy",
> > +                                                                BRIDGE=
_NAME);
> > +                dns =3D private_network_primary_dns;
> > +                DBG("Serving %s nameserver to clients", dns);
> > +        }
> > +
> > +        tethering_dhcp_server =3D 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 =3D -EOPNOTSUPP;
> > +                goto clean;
> > +        }
> > +
> > +        prefixlen =3D connman_ipaddress_calc_netmask_len(subnet_mask);
> > +        err =3D __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 =3D -EOPNOTSUPP;
> > +                goto clean;
> > +        }
> > +
> > +        err =3D __connman_ipv6pd_setup(BRIDGE_NAME);
> > +        if (err < 0 && err !=3D -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 =3D=3D -EOPNOTSUPP) || (err =3D=3D -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



--=20
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