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 (Tomasz Bursztyka)


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

Message: 1
Date: Mon, 29 Aug 2016 09:03:14 +0200
From: Tomasz Bursztyka <[email protected]>
To: Jose Blanquicet <[email protected]>, [email protected]
Subject: Re: [PATCH 1/3] technology: Add specific D-Bus methods for
        WPS connections
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252; format=flowed

Hi Jose,

Sorry for the (very) late review.

there seems to be 80chars limit errors.

> 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

> +
> +                     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 ||

> +             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

> +             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

> +             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 37
***************************************

Reply via email to