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