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