Send connman mailing list submissions to
        connman@lists.01.org

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
        connman-requ...@lists.01.org

You can reach the person managing the list at
        connman-ow...@lists.01.org

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


Today's Topics:

   1. [PATCH][v2] resolver: ensure that resolv.conf is populated
      with search domains and DNS servers in the correct order (Sam Nazarko)
   2. [PATCH 0/3] New WPS Implementation (Jose Blanquicet)
   3. [PATCH 1/3] technology: Add specific D-Bus methods for WPS
      connections (Jose Blanquicet)


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

Message: 1
Date: Fri, 22 Jul 2016 08:12:26 +0000
From: Sam Nazarko <em...@samnazarko.co.uk>
To: "connman@lists.01.org" <connman@lists.01.org>
Subject: [PATCH][v2] resolver: ensure that resolv.conf is populated
        with search domains and DNS servers in the correct order
Message-ID: <8bd5bf2768e74d088f809b955c834777@MBX019.indiv.local>
Content-Type: text/plain; charset="iso-8859-1"

>From 814d51ce06c8a44026e1265b62e3cdd818a3be72 Mon Sep 17 00:00:00 2001
From: Sam Nazarko <em...@samnazarko.co.uk>
Date: Thu, 21 Jul 2016 15:59:48 +0100
Subject: [PATCH] resolver: ensure that resolv.conf is populated with search
 domains and DNS servers in the correct order

Signed-off-by: Sam Nazarko <em...@samnazarko.co.uk>
---
 src/resolver.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/resolver.c b/src/resolver.c
index fbe4be7..c4adbc6 100644
--- a/src/resolver.c
+++ b/src/resolver.c
@@ -100,9 +100,9 @@ static int resolvfile_export(void)
         * MAXDNSRCH/MAXNS entries are used.
         */
 
-       for (count = 0, list = g_list_last(resolvfile_list);
+       for (count = 0, list = g_list_first(resolvfile_list);
                                                list && (count < MAXDNSRCH);
-                                               list = g_list_previous(list)) {
+                                               list = g_list_next(list)) {
                struct resolvfile_entry *entry = list->data;
 
                if (!entry->domain)
@@ -118,9 +118,9 @@ static int resolvfile_export(void)
        if (count)
                g_string_append_printf(content, "\n");
 
-       for (count = 0, list = g_list_last(resolvfile_list);
+       for (count = 0, list = g_list_first(resolvfile_list);
                                                list && (count < MAXNS);
-                                               list = g_list_previous(list)) {
+                                               list = g_list_next(list)) {
                struct resolvfile_entry *entry = list->data;
 
                if (!entry->server)
-- 
2.7.4

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

Message: 2
Date: Fri, 22 Jul 2016 15:54:05 +0200
From: Jose Blanquicet <blanqui...@gmail.com>
To: connman@lists.01.org
Subject: [PATCH 0/3] New WPS Implementation
Message-ID: <1469195648-19610-1-git-send-email-blanqui...@gmail.com>

Hi,

this is the WPS implementation following our previous agreements.

Please, let us know what do you think.

Best Regards,

        Jose Blanquicet


Jose Blanquicet (3):
  technology: Add specific D-Bus methods for WPS connections
  technology: Add WPS Cancel feature
  client: Add commands for new specific WPS D-Bus methods

 client/commands.c         | 125 ++++++++++++++++
 client/dbus_helpers.c     |   2 +-
 doc/agent-api.txt         |   6 +
 doc/connmanctl.1.in       |  14 +-
 doc/technology-api.txt    |  43 ++++++
 gsupplicant/gsupplicant.h |  18 +++
 gsupplicant/supplicant.c  | 321 ++++++++++++++++++++++++++++------------
 include/technology.h      |  11 ++
 plugins/wifi.c            | 364 +++++++++++++++++++++++++++++++++++++++++++---
 src/connman.h             |   1 +
 src/peer.c                |   5 +-
 src/technology.c          | 160 ++++++++++++++++++++
 12 files changed, 949 insertions(+), 121 deletions(-)

-- 
1.9.1



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

Message: 3
Date: Fri, 22 Jul 2016 15:54:06 +0200
From: Jose Blanquicet <blanqui...@gmail.com>
To: connman@lists.01.org
Subject: [PATCH 1/3] technology: Add specific D-Bus methods for WPS
        connections
Message-ID: <1469195648-19610-2-git-send-email-blanqui...@gmail.com>

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)
+
+                       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)
+
+                       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)
+               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));
+               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));
+               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,
+                                               
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.
+                                        */
+                                       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;
+
+               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)
+{
+       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) },
        { },
 };
 
-- 
1.9.1



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

Subject: Digest Footer

_______________________________________________
connman mailing list
connman@lists.01.org
https://lists.01.org/mailman/listinfo/connman


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

End of connman Digest, Vol 9, Issue 13
**************************************

Reply via email to