Send connman mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        https://lists.01.org/mailman/listinfo/connman
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."


Today's Topics:

   1. Re: [PATCH 1/3] technology: Add specific D-Bus methods for
      WPS connections (Jose Blanquicet)


----------------------------------------------------------------------

Message: 1
Date: Mon, 29 Aug 2016 11:52:10 +0200
From: Jose Blanquicet <[email protected]>
To: Tomasz Bursztyka <[email protected]>
Cc: [email protected],  Jose Blanquicet
        <[email protected]>,
        [email protected],  Patrik Flykt
        <[email protected]>
Subject: Re: [PATCH 1/3] technology: Add specific D-Bus methods for
        WPS connections
Message-ID:
        <CAFC8iJKPdk+p_oUEYh7oPgvDA1Uf18CsjPCr8=932s=aov-...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8

Hi Tomasz,

> Sorry for the (very) late review.

Don't worry. Thanks for the review.

> there seems to be 80chars limit errors.

I will check the patches with the linux's checkpatch as you suggested.
I think it is a problem with my text editor.

>> Two D-Bus methods were added to Technology Interface:
>>         - void Start_AP_WPS(string authentication)
>>         - void Start_STA_WPS(string authentication)
>>
>> With Start_STA_WPS method, WPS was completely detached from Service
>> and now ConnMan follows WiFi Alliance specifications. This patch
>> keeps current WPS implementation for compatibility support, but as
>> deprecated.
>> In case of multiple interfaces, Start_STA_WPS will prioritize the STA-only
>> interfaces if they exist, otherwise it will try on STA/AP ones and
>> only as last option it will use STA/AP/P2P interfaces. If the selected
>> interface is already connected to a service or p2p device, it will be
>> disconnected and then the WPS Session will start on it. Interfaces in AP
>> mode (Tethering enabled) will not be taken into account, they will be
>> skipped.
>> Start_STA_WPS method will finished successfully when WPS-Credentials are
>> correctly received. From that point, all the notifications(error or
>> success)
>> will be sent through the service corresponding to the received
>> credentials.
>>
>> In addition, by using Start_AP_WPS method, ConnMan now supports WPS in
>> AP mode (As registrar) which allows external devices get connect by using
>> WPS. For this method, if tethering is enabled it will start a WPS Session
>> on the corresponding tethering interface, otherwise it will reply with a
>> "PermissionDenied" error or "NotSupported" error if the interface has
>> tethering enabled but it does not support WPS.
>>
>> Technology documentation was updated.
>>
>>
>> ---
>>   doc/agent-api.txt         |   6 +
>>   doc/technology-api.txt    |  35 +++++
>>   gsupplicant/gsupplicant.h |  15 +++
>>   gsupplicant/supplicant.c  | 272 +++++++++++++++++++++++++--------------
>>   include/technology.h      |  10 ++
>>   plugins/wifi.c            | 322
>> +++++++++++++++++++++++++++++++++++++++++++---
>>   src/connman.h             |   1 +
>>   src/peer.c                |   5 +-
>>   src/technology.c          | 119 +++++++++++++++++
>>   9 files changed, 666 insertions(+), 119 deletions(-)
>>
>> diff --git a/doc/agent-api.txt b/doc/agent-api.txt
>> index aa7271d..7c09c10 100644
>> --- a/doc/agent-api.txt
>> +++ b/doc/agent-api.txt
>> @@ -139,6 +139,12 @@ Fields             string Name
>>                         In case of a RequestPeerAuthorization, this field
>> will
>>                         be set as mandatory.
>>   +                     To use this in order to get connected to a given
>> +                       services is deprecated and should not be used.
>> Methods
>> +                       Technology.Start_STA_WPS and
>> Technology.Start_AP_WPS
>> +                       are provided by ConnMan and user should use those
>> two
>> +                       instead.
>> +
>>                 string Username
>>                         Username for WISPr authentication. This field will
>> be
>> diff --git a/doc/technology-api.txt b/doc/technology-api.txt
>> index f22e9b2..b008374 100644
>> --- a/doc/technology-api.txt
>> +++ b/doc/technology-api.txt
>> @@ -40,6 +40,41 @@ Methods              dict GetProperties()  [deprecated]
>>                         via the PeersChanged signal from the manager
>>                         interface.
>>   +             void Start_AP_WPS(string authentication)
>
>
> Don't put '_'
>
>> +
>> +                       Start a WPS Session when the system is playing AP
>> +                       role (Tethering) in order to allow potential
>> Ex-STAs
>> +                       to get connected by using WPS.
>> +
>> +                       The argument indicates the WPS authentication
>> method
>> +                       which can be an empty string, if user wants to use
>> +                       push-button method, or a pin code if user wants to
>> +                       use the pin method.
>> +
>> +                       This method is supported only by WiFi technology.
>> +
>> +                       Possible Errors: [service].Error.InvalidArguments
>> +                                        [service].Error.PermissionDenied
>> +                                        [service].Error.NotSupported
>> +
>> +               void Start_STA_WPS(string authentication)
>
>
> Same here.
>
> Also, I wonder if it would not be simpler to have a unique method
> StartWPS(type, auth)
> type being STA or AP

Initially it was a unique method but after our previous discussion we
agreed to used two separated methods because of the parameters we
wanted to add before. Now, with just one parameter to merge them into
a single method again has completely sense, except for one of the
comments done by Patrik, please read my reply for him and then we can
discuss it again.

>> +
>> +                       Start a WPS Session in STA role in order to be
>> able
>> +                       to get connected with an Ex-AP with WPS
>> capabilities.
>> +
>> +                       The argument indicates the WPS authentication
>> method
>> +                       which can be an empty string, if user wants to use
>> +                       push-button method, or a pin code if user wants to
>> +                       use the pin method.
>> +
>> +                       This method is supported only by WiFi technology.
>> +
>> +                       Possible Errors: [service].Error.InvalidArguments
>> +                                        [service].Error.OperationAborted
>> +                                        [service].Error.OperationTimeout
>> +                                        [service].Error.NotConnected
>> +                                        [service].Error.NotSupported
>> +
>>   Signals               PropertyChanged(string name, variant value)
>>                         This signal indicates a changed value of the given
>> diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
>> index 26fd2ca..9944efd 100644
>> --- a/gsupplicant/gsupplicant.h
>> +++ b/gsupplicant/gsupplicant.h
>> @@ -155,6 +155,13 @@ struct _GSupplicantSSID {
>>     typedef struct _GSupplicantSSID GSupplicantSSID;
>>   +struct _GSupplicantWPSParams {
>> +       GSupplicantMode mode;
>> +       const char *pin;
>> +};
>> +
>> +typedef struct _GSupplicantWPSParams GSupplicantWPSParams;
>> +
>>   struct scan_ssid {
>>         unsigned char ssid[32];
>>         uint8_t ssid_len;
>> @@ -255,6 +262,11 @@ int
>> g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params,
>>                                         GSupplicantInterfaceCallback
>> callback,
>>                                         void *user_data);
>>   +int g_supplicant_interface_wps_start(GSupplicantInterface *interface,
>> +                                       GSupplicantWPSParams *wps,
>> +                                       GSupplicantInterfaceCallback
>> callback,
>> +                                       void *user_data);
>> +
>>   int g_supplicant_interface_connect(GSupplicantInterface *interface,
>>                                         GSupplicantSSID *ssid,
>>                                         GSupplicantInterfaceCallback
>> callback,
>> @@ -288,6 +300,7 @@ int
>> g_supplicant_interface_set_country(GSupplicantInterface *interface,
>>                                         GSupplicantCountryCallback
>> callback,
>>                                                         const char
>> *alpha2,
>>                                                         void *user_data);
>> +bool g_supplicant_interface_support_wps(GSupplicantInterface *interface);
>>   bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface);
>>   int g_supplicant_interface_set_p2p_device_config(GSupplicantInterface
>> *interface,
>>                                                 const char *device_name,
>> @@ -347,6 +360,8 @@ struct _GSupplicantCallbacks {
>>         void (*network_removed) (GSupplicantNetwork *network);
>>         void (*network_changed) (GSupplicantNetwork *network,
>>                                         const char *property);
>> +       void (*wps_event) (GSupplicantInterface *interface,
>> +                                       GSupplicantWpsState event, int
>> error);
>>         void (*peer_found) (GSupplicantPeer *peer);
>>         void (*peer_lost) (GSupplicantPeer *peer);
>>         void (*peer_changed) (GSupplicantPeer *peer,
>> diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
>> index 4cb533d..21342a0 100644
>> --- a/gsupplicant/supplicant.c
>> +++ b/gsupplicant/supplicant.c
>> @@ -180,6 +180,7 @@ struct _GSupplicantInterface {
>>         char *ifname;
>>         char *driver;
>>         char *bridge;
>> +       bool wps_support;
>>         struct _GSupplicantWpsCredentials wps_cred;
>>         GSupplicantWpsState wps_state;
>>         GHashTable *network_table;
>> @@ -285,6 +286,7 @@ struct interface_connect_data {
>>         union {
>>                 GSupplicantSSID *ssid;
>>                 GSupplicantPeerParams *peer;
>> +               GSupplicantWPSParams *wps;
>>         };
>>   };
>>   @@ -601,6 +603,19 @@ static void
>> callback_network_changed(GSupplicantNetwork *network,
>>         callbacks_pointer->network_changed(network, property);
>>   }
>>   +static void callback_wps_event(GSupplicantInterface *interface,
>> +                                       GSupplicantWpsState state, int
>> error)
>> +{
>> +       SUPPLICANT_DBG("");
>> +       if (!callbacks_pointer)
>> +               return;
>> +
>> +       if (!callbacks_pointer->wps_event)
>
>
> Put this test in the first if above with a ||

Ok.

>> +               return;
>> +
>> +       callbacks_pointer->wps_event(interface, state, error);
>> +}
>> +
>>   static void callback_peer_found(GSupplicantPeer *peer)
>>   {
>>         if (!callbacks_pointer)
>> @@ -2107,6 +2122,15 @@ static void interface_bss_removed(DBusMessageIter
>> *iter, void *user_data)
>>                 g_hash_table_remove(interface->network_table,
>> network->group);
>>   }
>>   +static void wps_process_credentials(DBusMessageIter *iter, void
>> *user_data)
>> +{
>> +       dbus_bool_t credentials = TRUE;
>> +
>> +       SUPPLICANT_DBG("");
>> +
>> +       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
>> &credentials);
>> +}
>> +
>>   static void set_config_methods(DBusMessageIter *iter, void *user_data)
>>   {
>>         const char *config_methods = "push_button";
>> @@ -2141,12 +2165,6 @@ static void interface_property(const char *key,
>> DBusMessageIter *iter,
>>                 debug_strvalmap("Mode capability", mode_capa_map,
>>                                                 interface->mode_capa);
>>   -
>> -               supplicant_dbus_property_set(interface->path,
>> -                               SUPPLICANT_INTERFACE ".Interface.WPS",
>> -                               "ConfigMethods",
>> DBUS_TYPE_STRING_AS_STRING,
>> -                               set_config_methods, NULL, NULL, NULL);
>> -
>>                 if (interface->ready)
>>                         callback_interface_added(interface);
>>   @@ -2158,6 +2176,20 @@ static void interface_property(const char *key,
>> DBusMessageIter *iter,
>>
>> interface);
>>                 if (interface->mode_capa &
>> G_SUPPLICANT_CAPABILITY_MODE_P2P)
>>                         interface->p2p_support = true;
>> +
>> +               if (interface->keymgmt_capa & G_SUPPLICANT_KEYMGMT_WPS) {
>> +                       interface->wps_support = true;
>> +
>> +                       supplicant_dbus_property_set(interface->path,
>> +                               SUPPLICANT_INTERFACE ".Interface.WPS",
>> +                               "ProcessCredentials",
>> DBUS_TYPE_BOOLEAN_AS_STRING,
>> +                               wps_process_credentials, NULL, NULL,
>> NULL);
>> +
>> +                       supplicant_dbus_property_set(interface->path,
>> +                               SUPPLICANT_INTERFACE ".Interface.WPS",
>> +                               "ConfigMethods",
>> DBUS_TYPE_STRING_AS_STRING,
>> +                               set_config_methods, NULL, NULL, NULL);
>> +               }
>>         } else if (g_strcmp0(key, "State") == 0) {
>>                 const char *str = NULL;
>>   @@ -2744,18 +2776,26 @@ static void signal_wps_credentials(const char
>> *path, DBusMessageIter *iter)
>>   static void wps_event_args(const char *key, DBusMessageIter *iter,
>>                         void *user_data)
>>   {
>> -       GSupplicantInterface *interface = user_data;
>> +       int *value = user_data;
>>   -     if (!key || !interface)
>> +       if (!key)
>>                 return;
>>         SUPPLICANT_DBG("Arg Key %s", key);
>> +
>> +       if (g_strcmp0(key, "config_error") == 0) {
>> +               dbus_message_iter_get_basic(iter, value);
>> +               SUPPLICANT_DBG("Configuration Error %d", *value);
>> +       }
>>   }
>>     static void signal_wps_event(const char *path, DBusMessageIter *iter)
>>   {
>>         GSupplicantInterface *interface;
>>         const char *name = NULL;
>> +       int config_error, error;
>> +
>> +#define WPS_CFG_ERROR_TIMEOUT                  16
>>         SUPPLICANT_DBG("");
>>   @@ -2767,19 +2807,35 @@ static void signal_wps_event(const char *path,
>> DBusMessageIter *iter)
>>         SUPPLICANT_DBG("Name: %s", name);
>>   -     if (g_strcmp0(name, "success") == 0)
>> +       if (dbus_message_iter_has_next(iter)) {
>> +               dbus_message_iter_next(iter);
>> +               supplicant_dbus_property_foreach(iter, wps_event_args,
>> &config_error);
>> +       }
>> +
>> +       if (g_strcmp0(name, "success") == 0) {
>>                 interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
>> -       else if (g_strcmp0(name, "fail") == 0)
>> +               error = 0;
>> +       }
>> +       else if (g_strcmp0(name, "fail") == 0) {
>>                 interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
>> -       else
>> -               interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
>> +               SUPPLICANT_DBG("WPS: Failed. Err = %d", config_error);
>>   -     if (!dbus_message_iter_has_next(iter))
>> +               if (config_error == WPS_CFG_ERROR_TIMEOUT)
>> +                       error = -ETIMEDOUT;
>> +               else
>> +                       error = -ECONNREFUSED;
>> +       }
>> +       else if (g_strcmp0(name, "pbc-overlap") == 0) {
>> +               interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
>> +               error = -ECONNABORTED;
>> +       } else {
>> +               // M2D Events are not forwarded
>> +               interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
>> +               error = -ECONNREFUSED;
>>                 return;
>> +       }
>>   -     dbus_message_iter_next(iter);
>> -
>> -       supplicant_dbus_property_foreach(iter, wps_event_args, interface);
>> +       callback_wps_event(interface, interface->wps_state, error);
>>   }
>>     static void create_peer_identifier(GSupplicantPeer *peer)
>> @@ -3496,6 +3552,14 @@ int
>> g_supplicant_interface_set_country(GSupplicantInterface *interface,
>>         return ret;
>>   }
>>   +bool g_supplicant_interface_support_wps(GSupplicantInterface
>> *interface)
>> +{
>> +       if (!interface)
>> +               return false;
>> +
>> +       return interface->wps_support;
>> +}
>> +
>>   bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface)
>>   {
>>         if (!interface)
>> @@ -4710,29 +4774,33 @@ static void interface_wps_start_result(const char
>> *error,
>>                 data->callback(err, data->interface, data->user_data);
>>         g_free(data->path);
>> -       g_free(data->ssid);
>> +       g_free(data->wps);
>>         dbus_free(data);
>>   }
>>     static void interface_add_wps_params(DBusMessageIter *iter, void
>> *user_data)
>>   {
>>         struct interface_connect_data *data = user_data;
>> -       GSupplicantSSID *ssid = data->ssid;
>> -       const char *role = "enrollee", *type;
>> +       GSupplicantWPSParams *wps = data->wps;
>> +       const char *role, *type;
>>         DBusMessageIter dict;
>>         SUPPLICANT_DBG("");
>>         supplicant_dbus_dict_open(iter, &dict);
>>   +     role = "enrollee";
>> +       if (wps->mode == G_SUPPLICANT_MODE_MASTER)
>> +               role = "registrar";
>> +
>>         supplicant_dbus_dict_append_basic(&dict, "Role",
>>                                                 DBUS_TYPE_STRING, &role);
>>         type = "pbc";
>> -       if (ssid->pin_wps) {
>> +       if (wps->pin) {
>>                 type = "pin";
>>                 supplicant_dbus_dict_append_basic(&dict, "Pin",
>> -                                       DBUS_TYPE_STRING, &ssid->pin_wps);
>> +                                       DBUS_TYPE_STRING, &wps->pin);
>>         }
>>         supplicant_dbus_dict_append_basic(&dict, "Type",
>> @@ -4741,36 +4809,41 @@ static void
>> interface_add_wps_params(DBusMessageIter *iter, void *user_data)
>>         supplicant_dbus_dict_close(iter, &dict);
>>   }
>>   -static void wps_start(const char *error, DBusMessageIter *iter, void
>> *user_data)
>> +int g_supplicant_interface_wps_start(GSupplicantInterface *interface,
>> +                                       GSupplicantWPSParams *wps,
>> +                                       GSupplicantInterfaceCallback
>> callback, void *user_data)
>>   {
>> -       struct interface_connect_data *data = user_data;
>> +       struct interface_connect_data *data;
>> +       int ret;
>>         SUPPLICANT_DBG("");
>>   -     if (error) {
>> -               SUPPLICANT_DBG("error: %s", error);
>> -               g_free(data->path);
>> -               g_free(data->ssid);
>> -               dbus_free(data);
>> -               return;
>> -       }
>> +       data = dbus_malloc0(sizeof(*data));
>> +       data->interface = interface;
>> +       data->path = g_strdup(interface->path);
>> +       data->callback = callback;
>> +       data->wps = wps;
>> +       data->user_data = user_data;
>>   -     supplicant_dbus_method_call(data->interface->path,
>> +       g_free(interface->wps_cred.key);
>> +       memset(&interface->wps_cred, 0, sizeof(struct
>> _GSupplicantWpsCredentials));
>> +
>> +       ret = supplicant_dbus_method_call(data->interface->path,
>>                         SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
>>                         interface_add_wps_params,
>>                         interface_wps_start_result, data, NULL);
>> -}
>> -
>> -static void wps_process_credentials(DBusMessageIter *iter, void
>> *user_data)
>> -{
>> -       dbus_bool_t credentials = TRUE;
>>   -     SUPPLICANT_DBG("");
>> +       if (ret < 0) {
>> +               SUPPLICANT_DBG("Error: WPS Session could not be started");
>> +               g_free(wps);
>> +               g_free(data->path);
>> +               dbus_free(data);
>> +               return ret;
>> +       }
>>   -     dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
>> &credentials);
>> +       return -EINPROGRESS;
>>   }
>>   -
>>   int g_supplicant_interface_connect(GSupplicantInterface *interface,
>>                                 GSupplicantSSID *ssid,
>>                                 GSupplicantInterfaceCallback callback,
>> @@ -4778,6 +4851,7 @@ int
>> g_supplicant_interface_connect(GSupplicantInterface *interface,
>>   {
>>         struct interface_connect_data *data;
>>         struct interface_data *intf_data;
>> +       GSupplicantWPSParams *wps;
>>         int ret = 0;
>>         if (!interface)
>> @@ -4788,6 +4862,20 @@ int
>> g_supplicant_interface_connect(GSupplicantInterface *interface,
>>         /* TODO: Check if we're already connected and switch */
>>   +     if (ssid->use_wps) {
>> +               wps = g_try_malloc0(sizeof(GSupplicantWPSParams));
>> +               if (!wps)
>> +                       return -ENOMEM;
>> +
>> +               memset(wps, 0, sizeof(*wps));
>
>
> No need of memset here, g_try_malloc0 already fills the allocated memory
> space with 0

You're right.

>> +               wps->mode = G_SUPPLICANT_MODE_INFRA;
>> +               wps->pin = ssid->pin_wps;
>> +
>> +               g_free(ssid);
>> +               return g_supplicant_interface_wps_start(interface,
>> +                                                       wps, callback,
>> user_data);
>> +       }
>> +
>>         data = dbus_malloc0(sizeof(*data));
>>         if (!data)
>>                 return -ENOMEM;
>> @@ -4798,70 +4886,60 @@ int
>> g_supplicant_interface_connect(GSupplicantInterface *interface,
>>         data->ssid = ssid;
>>         data->user_data = user_data;
>>   -     if (ssid->use_wps) {
>> -               g_free(interface->wps_cred.key);
>> -               memset(&interface->wps_cred, 0,
>> -                               sizeof(struct
>> _GSupplicantWpsCredentials));
>> -
>> -               ret = supplicant_dbus_property_set(interface->path,
>> -                       SUPPLICANT_INTERFACE ".Interface.WPS",
>> -                       "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
>> -                       wps_process_credentials, wps_start, data,
>> interface);
>> -       } else {
>> -               /* By the time there is a request for connect and the
>> network
>> -                * path is not NULL it means that connman has not removed
>> the
>> -                * previous network pointer. This can happen in the case
>> AP
>> -                * deauthenticated client and connman does not remove the
>> -                * previously connected network pointer. This causes
>> supplicant
>> -                * to reallocate the memory for struct wpa_ssid again even
>> if it
>> -                * is the same SSID. This causes memory usage of
>> wpa_supplicnat
>> -                * to go high. The idea here is that if the previously
>> connected
>> -                * network is not removed at the time of next connection
>> attempt
>> -                * check if the network path is not NULL. In case it is
>> non-NULL
>> -                * first remove the network and then once removal is
>> successful, add
>> -                * the network.
>> -                */
>> -
>> -               if (interface->network_path != NULL) {
>> -                       g_free(data->path);
>> -                       dbus_free(data);
>> +       /* By the time there is a request for connect and the network
>> +        * path is not NULL it means that connman has not removed the
>> +        * previous network pointer. This can happen in the case AP
>> +        * deauthenticated client and connman does not remove the
>> +        * previously connected network pointer. This causes supplicant
>> +        * to reallocate the memory for struct wpa_ssid again even if it
>> +        * is the same SSID. This causes memory usage of wpa_supplicnat
>> +        * to go high. The idea here is that if the previously connected
>> +        * network is not removed at the time of next connection attempt
>> +        * check if the network path is not NULL. In case it is non-NULL
>> +        * first remove the network and then once removal is successful,
>> add
>> +        * the network.
>> +        */
>>   -                     /*
>> -                        * If this add network is for the same network for
>> -                        * which wpa_supplicant already has a profile then
>> do
>> -                        * not need to add another profile. Only if the
>> -                        * profile that needs to get added is different
>> from
>> -                        * what is there in wpa_s delete the current one.
>> A
>> -                        * network is identified by its SSID,
>> security_type
>> -                        * and passphrase (private passphrase in case
>> security
>> -                        * type is 802.11x).
>> -                        */
>> -                       if (compare_network_parameters(interface, ssid)) {
>> -                               return -EALREADY;
>> -                       }
>> +       if (interface->network_path != NULL) {
>> +               g_free(data->path);
>> +               dbus_free(data);
>>   -                     intf_data = dbus_malloc0(sizeof(*intf_data));
>> -                       if (!intf_data)
>> -                               return -ENOMEM;
>> -
>> -                       intf_data->interface = interface;
>> -                       intf_data->path = g_strdup(interface->path);
>> -                       intf_data->callback = callback;
>> -                       intf_data->ssid = ssid;
>> -                       intf_data->user_data = user_data;
>> -                       intf_data->network_remove_in_progress = TRUE;
>> -                       network_remove(intf_data);
>> -               } else {
>> -                       ret = supplicant_dbus_method_call(interface->path,
>> -                                       SUPPLICANT_INTERFACE ".Interface",
>> "AddNetwork",
>> -                                       interface_add_network_params,
>> -                                       interface_add_network_result,
>> data,
>> -                                       interface);
>> +               /*
>> +                * If this add network is for the same network for
>> +                * which wpa_supplicant already has a profile then do
>> +                * not need to add another profile. Only if the
>> +                * profile that needs to get added is different from
>> +                * what is there in wpa_s delete the current one. A
>> +                * network is identified by its SSID, security_type
>> +                * and passphrase (private passphrase in case security
>> +                * type is 802.11x).
>> +                */
>> +               if (compare_network_parameters(interface, ssid)) {
>> +                       return -EALREADY;
>>                 }
>> -        }
>> +
>> +               intf_data = dbus_malloc0(sizeof(*intf_data));
>
>
> switch to glib memory function. We mixed both glib/dbus in the past, but
> it's an inconsistent usage

This is something not added by this patch. I would prefer to not mix
patches, I think it should be done into a new patch where we
completely migrate toward glib memory functions.

>> +               if (!intf_data)
>> +                       return -ENOMEM;
>> +
>> +               intf_data->interface = interface;
>> +               intf_data->path = g_strdup(interface->path);
>> +               intf_data->callback = callback;
>> +               intf_data->ssid = ssid;
>> +               intf_data->user_data = user_data;
>> +               intf_data->network_remove_in_progress = TRUE;
>> +               network_remove(intf_data);
>> +       } else {
>> +               ret = supplicant_dbus_method_call(interface->path,
>> +                               SUPPLICANT_INTERFACE ".Interface",
>> "AddNetwork",
>> +                               interface_add_network_params,
>> +                               interface_add_network_result, data,
>> +                               interface);
>> +       }
>>         if (ret < 0) {
>>                 g_free(data->path);
>> +               g_free(data->ssid);
>>                 dbus_free(data);
>>                 return ret;
>>         }
>> diff --git a/include/technology.h b/include/technology.h
>> index d7fcdde..771cbb6 100644
>> --- a/include/technology.h
>> +++ b/include/technology.h
>> @@ -34,6 +34,11 @@ extern "C" {
>>    * @short_description: Functions for handling technology details
>>    */
>>   +enum connman_technology_wps_mode {
>> +       CONNMAN_TECHNOLOGY_WPS_STA_MODE         = 0,
>> +       CONNMAN_TECHNOLOGY_WPS_AP_MODE          = 1,
>> +};
>> +
>>   struct connman_technology;
>>     void connman_technology_tethering_notify(struct connman_technology
>> *technology,
>> @@ -45,6 +50,8 @@ void connman_technology_regdom_notify(struct
>> connman_technology *technology,
>>   bool connman_technology_get_wifi_tethering(const char **ssid,
>>                                                         const char **psk);
>>   bool connman_technology_is_tethering_allowed(enum connman_service_type
>> type);
>> +void connman_technology_reply_start_sta_wps(struct connman_technology
>> *technology,
>> +                                                       int error);
>>     struct connman_technology_driver {
>>         const char *name;
>> @@ -62,6 +69,9 @@ struct connman_technology_driver {
>>                                 const char *bridge, bool enabled);
>>         int (*set_regdom) (struct connman_technology *technology,
>>                                                 const char *alpha2);
>> +       int (*start_wps) (struct connman_technology *technology,
>> +                                               enum
>> connman_technology_wps_mode mode,
>> +                                               const char *wps_pin);
>>   };
>>     int connman_technology_driver_register(struct
>> connman_technology_driver *driver);
>> diff --git a/plugins/wifi.c b/plugins/wifi.c
>> index 9d56671..53e826a 100644
>> --- a/plugins/wifi.c
>> +++ b/plugins/wifi.c
>> @@ -145,6 +145,7 @@ struct wifi_data {
>>         unsigned int p2p_connection_timeout;
>>         struct connman_peer *pending_peer;
>>         GSList *peers;
>> +       bool p2p_connected;
>>         bool p2p_connecting;
>>         bool p2p_device;
>>         int servicing;
>> @@ -404,6 +405,29 @@ static int peer_disconnect(struct connman_peer *peer)
>>         return ret;
>>   }
>>   +static int peer_disconnect_all(struct wifi_data *wifi)
>> +{
>> +       GSList *list;
>> +       int result = 0, err = -EALREADY;
>> +
>> +       DBG("");
>> +
>> +       for (list = wifi->peers; list; list = list->next) {
>> +               struct connman_peer *peer = list->data;
>> +               GSupplicantPeer *gs_peer =
>> +
>> g_supplicant_interface_peer_lookup(wifi->interface,
>
>
> beware of 80 chars line limit.
>
>
>> +
>> connman_peer_get_identifier(peer));
>> +
>> +               if (g_supplicant_peer_is_in_a_group(gs_peer)) {
>> +                       err = peer_disconnect(peer);
>> +                       if (err != -EINPROGRESS)
>> +                               result = err;
>> +               }
>> +       }
>> +
>> +       return result;
>> +}
>> +
>>   struct peer_service_registration {
>>         peer_service_registration_cb_t callback;
>>         void *user_data;
>> @@ -1522,6 +1546,7 @@ static int wifi_disable(struct connman_device
>> *device)
>>                 return -ENODEV;
>>         wifi->connected = false;
>> +       wifi->p2p_connected = false;
>>         wifi->disconnecting = false;
>>         if (wifi->pending_network)
>> @@ -2079,6 +2104,7 @@ static int network_connect(struct connman_network
>> *network)
>>         struct wifi_data *wifi;
>>         GSupplicantInterface *interface;
>>         GSupplicantSSID *ssid;
>> +       int ret;
>>         DBG("network %p", network);
>>   @@ -2100,29 +2126,32 @@ static int network_connect(struct
>> connman_network *network)
>>         if (wifi->disconnecting) {
>>                 wifi->pending_network = network;
>>                 g_free(ssid);
>> -       } else {
>> +               return -EINPROGRESS;
>> +       }
>>   -             /*
>> -                * This is the network that is going to get plumbed into
>> wpa_s
>> -                * Mark the previous network that is plumbed in wpa_s as
>> not
>> -                * connectable and then the current one as connectable.
>> -                * This flag will be used to ensure that the network that
>> is
>> -                * sitting in wpa_s never gets marked unavailable even
>> though
>> -                * the scan did not find this network.
>> -                */
>> -               if (wifi->network) {
>> -                       connman_network_set_connectable(wifi->network,
>> false);
>> -               }
>> +       /*
>> +        * This is the network that is going to get plumbed into wpa_s
>> +        * Mark the previous network that is plumbed in wpa_s as not
>> +        * connectable and then the current one as connectable.
>> +        * This flag will be used to ensure that the network that is
>> +        * sitting in wpa_s never gets marked unavailable even though
>> +        * the scan did not find this network.
>> +        */
>> +       if (wifi->network) {
>> +               connman_network_set_connectable(wifi->network, false);
>> +       }
>>   -             wifi->network = connman_network_ref(network);
>> -               connman_network_set_connectable(wifi->network, true);
>> -               wifi->retries = 0;
>> +       wifi->network = connman_network_ref(network);
>> +       connman_network_set_connectable(wifi->network, true);
>> +       wifi->retries = 0;
>>   -             return g_supplicant_interface_connect(interface, ssid,
>> -                                               connect_callback,
>> network);
>> -       }
>> +       ret = g_supplicant_interface_connect(interface, ssid,
>> +                                       connect_callback, network);
>>   -     return -EINPROGRESS;
>> +       if (ret < 0 && ret != -EINPROGRESS)
>> +               g_free(ssid);
>> +
>> +       return ret;
>>   }
>>     static void disconnect_callback(int result, GSupplicantInterface
>> *interface,
>> @@ -2824,6 +2853,77 @@ static void apply_peer_services(GSupplicantPeer
>> *peer,
>>         }
>>   }
>>   +static void wps_event(GSupplicantInterface *interface,
>> +
>> GSupplicantWpsState state, int error)
>> +{
>> +       unsigned int ssid_len;
>> +       const char *wps_ssid, *current_ssid;
>> +       GSList *list;
>> +
>> +       struct wifi_data *wifi =
>> g_supplicant_interface_get_data(interface);
>> +
>> +       /* Do nothing here for P2P Connections */
>> +       if (wifi->p2p_connecting)
>> +               return;
>> +
>> +       switch (state) {
>> +               case G_SUPPLICANT_WPS_STATE_SUCCESS:
>> +                       /*
>> +                        * At this point the WPS Provisioning has
>> successfully finished, so
>> +                        * let's reply to Start_STA_WPS method with
>> success end status.
>> +                        *
>> +                        * In addition, from this point the SSID of the AP
>> we are connecting
>> +                        * is known thus we look for the corresponding
>> ConnMan network and
>> +                        * set it as the current active network with WPS
>> as authentication
>> +                        * method. Then, any further error or successful
>> completion in the
>> +                        * connection will be reported thru the
>> corresponding service.
>> +                        */
>> +
>> +                       DBG("WPS-STA-Event: Success");
>> +
>> +                       wps_ssid =
>> g_supplicant_interface_get_wps_ssid(interface, &ssid_len);
>> +
>> +                       if (wifi->network) {
>> +                               current_ssid =
>> connman_network_get_string(wifi->network, "Name");
>> +                               if (memcmp(current_ssid, wps_ssid,
>> ssid_len) == 0) {
>> +                                       /*
>> +                                        * This could only happen when the
>> WPS session was started
>> +                                        * using the service/agent
>> procedure. Remember it is deprecated.
>
>
> 80 chars limit (unless my mail client is acting weird.)
>
> Run linux's checkpatch on your patches before sending them, to verify.
>
>
>> +                                        */
>> +                                       DBG("Network/Service is already
>> aware it is using WPS");
>> +                                       return;
>> +                               }
>> +                       }
>> +
>> +                       for (list = wifi->networks; list; list =
>> list->next) {
>> +                               struct connman_network *network =
>> list->data;
>> +                               const char *str =
>> connman_network_get_string(network, "Name");
>> +
>> +                               if (memcmp(str, wps_ssid, ssid_len) != 0)
>> +                                       continue;
>> +
>> +                               DBG("Setting network %s as active with
>> WPS", str);
>> +                               connman_network_set_bool(network,
>> "WiFi.UseWPS", true);
>> +
>> +                               wifi->network =
>> connman_network_ref(network);
>> +
>> connman_network_set_connectable(wifi->network, true);
>> +                               wifi->retries = 0;
>> +
>> +
>> connman_technology_reply_start_sta_wps(wifi_technology, 0);
>> +                               return;
>> +                       }
>> +
>> +                       break;
>> +               case G_SUPPLICANT_WPS_STATE_FAIL:
>> +                       DBG("WPS-STA-Event: Fail %d", error);
>> +
>> connman_technology_reply_start_sta_wps(wifi_technology, error);
>> +                       break;
>> +               default:
>> +                       DBG("WPS-STA-Event: Not defined");
>> +                       return;
>> +       }
>> +}
>> +
>>   static void peer_found(GSupplicantPeer *peer)
>>   {
>>         GSupplicantInterface *iface =
>> g_supplicant_peer_get_interface(peer);
>> @@ -2930,6 +3030,10 @@ static void peer_changed(GSupplicantPeer *peer,
>> GSupplicantPeerState state)
>>                 break;
>>         }
>>   +     if (p_state == CONNMAN_PEER_STATE_FAILURE ||
>> +                                       p_state ==
>> CONNMAN_PEER_STATE_IDLE)
>> +               wifi->p2p_connected = false;
>> +
>>         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
>>                                         p_state ==
>> CONNMAN_PEER_STATE_FAILURE) {
>>                 if (wifi->p2p_connecting
>> @@ -2946,6 +3050,8 @@ static void peer_changed(GSupplicantPeer *peer,
>> GSupplicantPeerState state)
>>                 GSupplicantInterface *g_iface;
>>                 struct wifi_data *g_wifi;
>>   +             wifi->p2p_connected = true;
>> +
>>                 g_iface = g_supplicant_peer_get_group_interface(peer);
>>                 if (!g_iface)
>>                         return;
>> @@ -3018,6 +3124,7 @@ static const GSupplicantCallbacks callbacks = {
>>         .network_added          = network_added,
>>         .network_removed        = network_removed,
>>         .network_changed        = network_changed,
>> +       .wps_event              = wps_event,
>>         .peer_found             = peer_found,
>>         .peer_lost              = peer_lost,
>>         .peer_changed           = peer_changed,
>> @@ -3309,6 +3416,182 @@ static int tech_set_regdom(struct
>> connman_technology *technology, const char *al
>>         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
>>   }
>>   +static void start_wps_callback(int result, GSupplicantInterface
>> *interface,
>> +                                                       void *user_data)
>> +{
>> +       GSupplicantWPSParams *wps = user_data;
>> +
>> +       DBG("");
>> +
>> +       if (result) {
>> +               DBG("Error while starting WPS Session %d", result);
>> +
>> +               if (wps->mode == G_SUPPLICANT_MODE_INFRA)
>> +
>> connman_technology_reply_start_sta_wps(wifi_technology, -EINVAL);
>> +       }
>> +}
>> +
>> +/*
>> + * Start WPS Session in STA mode.
>> + *
>> + * @skip_ap: When it is TRUE then this function will not try to start WPS
>> on
>> + * the interfaces that support AP mode. Those will be skipped.
>> + * @skip_p2p: When it is TRUE then this function will not try to start
>> WPS on
>> + * the interfaces that support P2P mode. Those will be skipped.
>> + *
>> + * It is always assumed that P2P support always implies AP support
>> + */
>> +static int start_sta_wps(const char *wps_pin, bool skip_ap, bool
>> skip_p2p)
>> +{
>> +       GList *list;
>> +       GSupplicantInterface *interface;
>> +       GSupplicantWPSParams *wps;
>> +       struct wifi_data *wifi;
>> +
>> +       const char *ifname;
>> +       bool p2p_support, ap_support, sta_support, wps_support;
>> +       unsigned int mode;
>> +       int err;
>> +
>> +
>> +       for (list = iface_list; list; list = list->next) {
>> +               wifi = list->data;
>> +
>> +               interface = wifi->interface;
>> +               ifname =
>> g_supplicant_interface_get_ifname(wifi->interface);
>> +               mode = g_supplicant_interface_get_mode(interface);
>> +
>> +               wps_support =
>> g_supplicant_interface_support_wps(interface);
>> +               p2p_support = g_supplicant_interface_has_p2p(interface);
>> +               sta_support = mode & G_SUPPLICANT_CAPABILITY_MODE_INFRA ?
>> true : false;
>> +               ap_support = !(wifi->ap_supported ==
>> WIFI_AP_NOT_SUPPORTED) &&
>> +                                               (mode &
>> G_SUPPLICANT_CAPABILITY_MODE_AP) ? true : false;
>
>
> same here
>
>
>> +
>> +               if (!wps_support || !sta_support) {
>> +                       DBG("Skipping %s. Required capabilities are
>> missing", ifname);
>> +                       continue;
>> +               }
>> +
>> +               if (p2p_support && skip_p2p) {
>> +                       DBG("Skipping %s. It also supports P2P/AP modes",
>> ifname);
>> +                       continue;
>> +               }
>> +
>> +               if ((ap_support && !p2p_support) && skip_ap) {
>> +                       DBG("Skipping %s. It also supports AP mode",
>> ifname);
>> +                       continue;
>> +               }
>> +
>> +               if (wifi->tethering) {
>> +                       DBG("Skipping %s. It is busy (Tethering)",
>> ifname);
>> +                       continue;
>> +               }
>> +
>> +               if (wifi->connected && wifi->network) {
>> +                       err = network_disconnect(wifi->network);
>> +                       if (err < 0)
>> +                               return err;
>> +               }
>> +
>> +               if (wifi->p2p_connected) {
>> +                       err = peer_disconnect_all(wifi);
>> +                       if (err < 0)
>> +                               return err;
>> +               }
>> +
>> +               wps = g_try_malloc0(sizeof(GSupplicantWPSParams));
>> +               if (!wps)
>> +                       return -ENOMEM;
>> +
>> +               memset(wps, 0, sizeof(*wps));
>> +               wps->pin = wps_pin;
>> +               wps->mode = G_SUPPLICANT_MODE_INFRA;
>> +
>> +               DBG("Trying to start WPS on %s", ifname);
>> +               return g_supplicant_interface_wps_start(interface, wps,
>> +                                       start_wps_callback, wps);
>> +       }
>> +
>> +       return -EOPNOTSUPP;
>> +}
>> +
>> +static int sta_wps(const char *wps_pin)
>> +{
>> +       int err;
>> +
>> +       /* It is preferred to use the STA-only interfaces */
>> +       DBG("Try on STA-only interfaces");
>> +       err = start_sta_wps(wps_pin, true, true);
>> +       if (err == -EOPNOTSUPP) {
>> +               /*
>> +                * Any STA-only interfaces available, so let's try on
>> STA/AP
>> +                * interfaces. P2P interface will be only considered in
>> the case it
>> +                * is the last option.
>> +                */
>> +               DBG("Try on STA/AP interfaces");
>> +
>> +               err = start_sta_wps(wps_pin, false, true);
>> +               if (err == -EOPNOTSUPP) {
>> +                       /*
>> +                        * Neither STA/AP interfaces are available thus
>> let's try on
>> +                        * STA/AP/P2P interfaces.
>> +                        */
>> +                       DBG("Try on STA/AP/P2P interfaces");
>> +
>> +                       return start_sta_wps(wps_pin, true, false);
>> +               }
>> +       }
>> +
>> +       return err;
>> +}
>> +
>> +static int tech_start_wps(struct connman_technology *technology,
>> +                                                               enum
>> connman_technology_wps_mode mode,
>> +                                                               const char
>> *wps_pin)
>
>
> ditto
>
>
>> +{
>> +       GList *list;
>> +       GSupplicantInterface *interface;
>> +       struct wifi_data *wifi;
>> +       GSupplicantWPSParams *wps;
>> +
>> +       DBG("");
>> +
>> +       if (mode == CONNMAN_TECHNOLOGY_WPS_STA_MODE)
>> +               return sta_wps(wps_pin);
>> +
>> +       /*
>> +        * For WPS in AP mode, we just need to look for the interface on
>> which
>> +        * tethering is enabled and start WPS on it.
>> +        */
>> +       for (list = iface_list; list; list = list->next) {
>> +               wifi = list->data;
>> +
>> +               if (!wifi->tethering)
>> +                       continue;
>> +
>> +               interface = wifi->interface;
>> +
>> +               if (!g_supplicant_interface_support_wps(interface)) {
>> +                       DBG("Error: WPS is not supported on tethering
>> interface");
>> +                       return -EOPNOTSUPP;
>> +               }
>> +
>> +               wps = g_try_malloc0(sizeof(GSupplicantWPSParams));
>> +               if (!wps)
>> +                       return -ENOMEM;
>> +
>> +               memset(wps, 0, sizeof(*wps));
>> +               wps->pin = wps_pin;
>> +               wps->mode = G_SUPPLICANT_MODE_MASTER;
>> +
>> +               return g_supplicant_interface_wps_start(interface, wps,
>> +                                       start_wps_callback, wps);
>> +       }
>> +
>> +       return -EOPNOTSUPP;
>> +}
>> +
>> +
>>   static struct connman_technology_driver tech_driver = {
>>         .name           = "wifi",
>>         .type           = CONNMAN_SERVICE_TYPE_WIFI,
>> @@ -3316,6 +3599,7 @@ static struct connman_technology_driver tech_driver
>> = {
>>         .remove         = tech_remove,
>>         .set_tethering  = tech_set_tethering,
>>         .set_regdom     = tech_set_regdom,
>> +       .start_wps      = tech_start_wps,
>>   };
>>     static int wifi_init(void)
>> diff --git a/src/connman.h b/src/connman.h
>> index e849ed8..fb17e92 100644
>> --- a/src/connman.h
>> +++ b/src/connman.h
>> @@ -819,6 +819,7 @@ int __connman_peer_service_unregister(const char
>> *owner,
>>                                         int specification_length,
>>                                         const unsigned char *query,
>>                                         int query_length, int version);
>> +enum connman_peer_wps_method __connman_check_wps_method(const char
>> *wpspin);
>>     #include <connman/session.h>
>>   diff --git a/src/peer.c b/src/peer.c
>> index ad4e445..0e418ac 100644
>> --- a/src/peer.c
>> +++ b/src/peer.c
>> @@ -545,8 +545,7 @@ static const char *get_dbus_sender(struct connman_peer
>> *peer)
>>         return dbus_message_get_sender(peer->pending);
>>   }
>>   -static enum connman_peer_wps_method check_wpspin(struct connman_peer
>> *peer,
>> -                                                       const char
>> *wpspin)
>> +enum connman_peer_wps_method __connman_check_wps_method(const char
>> *wpspin)
>>   {
>>         int len, i;
>>   @@ -591,7 +590,7 @@ static void request_authorization_cb(struct
>> connman_peer *peer,
>>                 goto out;
>>         }
>>   -     wps_method = check_wpspin(peer, wpspin);
>> +       wps_method = __connman_check_wps_method(wpspin);
>>         err = peer_driver->connect(peer, wps_method, wpspin);
>>         if (err == -EINPROGRESS)
>> diff --git a/src/technology.c b/src/technology.c
>> index 660af52..89b3130 100644
>> --- a/src/technology.c
>> +++ b/src/technology.c
>> @@ -74,6 +74,13 @@ struct connman_technology {
>>         DBusMessage *pending_reply;
>>         guint pending_timeout;
>>   +     /*
>> +        * Used to handle WPS errors within the two-minute interval.
>> +        * It is done only for WPS in STA mode, because for AP the
>> +        * wpa_supplicant does not report any events/errors.
>> +        */
>> +       DBusMessage *wps_reply;
>> +
>>         GSList *scan_pending;
>>         bool rfkill_driven;
>> @@ -557,6 +564,112 @@ static void technology_removed_signal(struct
>> connman_technology *technology)
>>                         DBUS_TYPE_INVALID);
>>   }
>>   +void connman_technology_reply_start_sta_wps(struct connman_technology
>> *technology,
>> +                                                       int error)
>> +{
>> +       DBusMessage *reply;
>> +
>> +       if (!technology->wps_reply)
>> +               return;
>> +
>> +       if (error < 0)
>> +               reply = __connman_error_failed(technology->wps_reply,
>> -error);
>> +       else
>> +               reply = g_dbus_create_reply(technology->wps_reply,
>> DBUS_TYPE_INVALID);
>> +
>> +       g_dbus_send_message(connection, reply);
>> +
>> +       dbus_message_unref(technology->wps_reply);
>> +       technology->wps_reply = NULL;
>> +}
>> +
>> +static int start_wps(struct connman_technology *technology, DBusMessage
>> *msg,
>> +                                                       enum
>> connman_technology_wps_mode mode)
>> +{
>> +       GSList *tech_drivers;
>> +       DBusMessageIter iter;
>> +       enum connman_peer_wps_method wps_method;
>> +       const char *auth;
>> +       int err, result = -EOPNOTSUPP;
>> +
>> +       if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
>> +               return -EOPNOTSUPP;
>> +
>> +       __sync_synchronize();
>> +       if (!technology->enabled)
>> +               return -EACCES;
>> +
>> +       if (!dbus_message_iter_init(msg, &iter))
>> +               return -EINVAL;
>> +
>> +       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
>> +               return -EINVAL;
>> +
>> +       dbus_message_iter_get_basic(&iter, &auth);
>> +
>> +       wps_method = __connman_check_wps_method(auth);
>> +       if (wps_method == CONNMAN_PEER_WPS_UNKNOWN)
>> +               return -EINVAL;
>> +       if (wps_method == CONNMAN_PEER_WPS_PBC)
>> +               auth = NULL;
>> +
>> +       for (tech_drivers = technology->driver_list; tech_drivers;
>> +                tech_drivers = g_slist_next(tech_drivers)) {
>> +               struct connman_technology_driver *driver =
>> tech_drivers->data;
>> +
>> +               if (!driver || !driver->start_wps ||
>> +                                       driver->type !=
>> CONNMAN_SERVICE_TYPE_WIFI)
>> +                       continue;
>> +
>> +               err = driver->start_wps(technology, mode, auth);
>> +
>> +               if (result == -EINPROGRESS)
>> +                       continue;
>> +
>> +               if (err == -EINPROGRESS)
>> +                       result = err;
>> +       }
>> +
>> +       return result;
>> +}
>> +
>> +static DBusMessage *start_ap_wps(DBusConnection *conn, DBusMessage *msg,
>> +                                                       void *user_data)
>> +{
>> +       struct connman_technology *technology = user_data;
>> +       int err;
>> +
>> +       /* It is required to enable tethering before starting WPS in AP
>> mode */
>> +       if (!technology->tethering) {
>> +               DBG("Error: Tethering is required");
>> +               return __connman_error_permission_denied(msg);
>> +       }
>> +
>> +       err = start_wps(technology, msg, CONNMAN_TECHNOLOGY_WPS_AP_MODE);
>> +       if (err == -EINPROGRESS)
>> +               return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
>> +
>> +       return __connman_error_failed(msg, -err);
>> +}
>> +
>> +static DBusMessage *start_sta_wps(DBusConnection *conn, DBusMessage *msg,
>> +                                                       void *user_data)
>> +{
>> +       struct connman_technology *technology = user_data;
>> +       int err;
>> +
>> +       if (technology->wps_reply)
>> +               connman_technology_reply_start_sta_wps(technology,
>> -ECONNABORTED);
>> +
>> +       err = start_wps(technology, msg, CONNMAN_TECHNOLOGY_WPS_STA_MODE);
>> +       if (err == -EINPROGRESS) {
>> +               technology->wps_reply = dbus_message_ref(msg);
>> +               return NULL;
>> +       }
>> +
>> +       return __connman_error_failed(msg, -err);
>> +}
>> +
>>   static DBusMessage *get_properties(DBusConnection *conn,
>>                                         DBusMessage *message, void
>> *user_data)
>>   {
>> @@ -1077,6 +1190,12 @@ static const GDBusMethodTable technology_methods[]
>> = {
>>                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
>>                         NULL, set_property) },
>>         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
>> +       { GDBUS_ASYNC_METHOD("Start_AP_WPS",
>> +                       GDBUS_ARGS({ "authentication", "s" }),
>> +                       NULL, start_ap_wps) },
>> +       { GDBUS_ASYNC_METHOD("Start_STA_WPS",
>> +                       GDBUS_ARGS({ "authentication", "s" }),
>> +                       NULL, start_sta_wps) },
>>         { },
>>   };
>>
>
>
>


------------------------------

Subject: Digest Footer

_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman


------------------------------

End of connman Digest, Vol 10, Issue 40
***************************************

Reply via email to