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. [PATCH v2 2/4] wps: add new WPS API implementation
([email protected])
----------------------------------------------------------------------
Message: 1
Date: Fri, 31 Aug 2018 11:11:51 +0000
From: <[email protected]>
To: <[email protected]>
Cc: <[email protected]>, <[email protected]>,
<[email protected]>
Subject: [PATCH v2 2/4] wps: add new WPS API implementation
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="us-ascii"
This is main part of this patch series.
Add new WPS start API which does not specify any service.
Add the handler which receive WPS credential and force save information
into applicable service.
Add new status property for display WPS status.
Remove exist WPS API.
Signed-off-by: n-itaya <[email protected]>
---
plugins/wifi.c | 671 +++++++++++++++++++++++++++++++++++++++++++++++--
src/connman.h | 6 +
src/error.c | 16 ++
src/peer.c | 5 +-
src/service.c | 21 ++
5 files changed, 692 insertions(+), 27 deletions(-)
diff --git a/plugins/wifi.c b/plugins/wifi.c
index dc08c6af..12f039ef 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -42,6 +42,7 @@
#include <glib.h>
#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman.h>
#include <connman/plugin.h>
#include <connman/inet.h>
#include <connman/device.h>
@@ -123,6 +124,12 @@ struct wifi_tethering_info {
GSupplicantSSID *ssid;
};
+struct wifi_wps_offered_data {
+ struct connman_service *service;
+ char *expect_ident;
+ char *passphrase;
+};
+
struct wifi_data {
char *identifier;
struct connman_device *device;
@@ -156,11 +163,19 @@ 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;
int disconnect_code;
int assoc_code;
+
+ bool wps_running;
+ bool wps_success;
+ unsigned int wps_timeout;
+ GSList *wps_offered_list;
+ bool wps_after_scan;
+ GSupplicantWPSParams wps_params;
};
static GList *iface_list = NULL;
@@ -174,6 +189,26 @@ static int tech_set_tethering(struct connman_technology
*technology,
const char *identifier, const char *passphrase,
const char *bridge, bool enabled);
+/* WPS Functions */
+#define WPS_TIMEOUT_INTERVAL_MSECS (125 * 1000)
+
+static void wps_event_success(GSupplicantInterface *interface);
+static void wps_event_fail(GSupplicantInterface *interface, int error);
+static struct wifi_wps_offered_data *wps_alloc_offered_data(
+ struct wifi_data *wifi, const char *group,
+ const char *passphrase);
+static void wps_free_offered_data(struct wifi_wps_offered_data *wps_data);
+static unsigned int wps_get_accepted_count(struct wifi_data *wifi);
+static unsigned int wps_get_offered_count(struct wifi_data *wifi);
+static bool wps_try_update_services(struct wifi_data *wifi);
+static void wps_finish(struct wifi_data *wifi, int error);
+static void wps_cleanup(struct wifi_data *wifi);
+static void wps_scan_callback(int result, GSupplicantInterface *interface,
+ void *user_data);
+static gboolean wps_timeout(gpointer data);
+static void wps_retry_callback(int result, GSupplicantInterface *interface,
+ void *user_data);
+
static int p2p_tech_probe(struct connman_technology *technology)
{
p2p_technology = technology;
@@ -417,6 +452,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;
@@ -1583,6 +1641,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)
@@ -2176,9 +2235,6 @@ static void ssid_init(GSupplicantSSID *ssid, struct
connman_network *network)
"WiFi.PrivateKeyPassphrase");
ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
- ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
- ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
-
if (connman_setting_get_bool("BackgroundScanning"))
ssid->bgscan = BGSCAN_DEFAULT;
}
@@ -2199,6 +2255,9 @@ static int network_connect(struct connman_network
*network)
if (!wifi)
return -ENODEV;
+ if (wifi->wps_running)
+ return -EBUSY;
+
ssid = g_try_malloc0(sizeof(GSupplicantSSID));
if (!ssid)
return -ENOMEM;
@@ -2375,6 +2434,8 @@ static bool handle_wps_completion(GSupplicantInterface
*interface,
{
bool wps;
+ DBG("");
+
wps = connman_network_get_bool(network, "WiFi.UseWPS");
if (wps) {
const unsigned char *ssid, *wps_ssid;
@@ -2486,9 +2547,40 @@ static void interface_state(GSupplicantInterface
*interface)
finalize_interface_creation(wifi);
}
+ if (wifi->wps_running) {
+ DBG("WPS running");
+ switch (state) {
+ case G_SUPPLICANT_STATE_SCANNING:
+ if (!wifi->wps_success)
+ connman_technology_wps_state_change_notify
+ (wifi_technology, "scan");
+ return;
+ case G_SUPPLICANT_STATE_ASSOCIATED:
+ connman_technology_wps_state_change_notify
+ (wifi_technology, "processing");
+ return;
+ case G_SUPPLICANT_STATE_DISCONNECTED:
+ if (wifi->wps_success) {
+ if (wps_try_update_services(wifi)) {
+ wps_finish(wifi, 0);
+ } else {
+ wifi->wps_after_scan = true;
+ DBG("Need scan");
+ reset_autoscan(wifi->device);
+ throw_wifi_scan(device,
+ wps_scan_callback);
+ }
+ }
+ return;
+ default:
+ return;
+ }
+ }
+
network = wifi->network;
- if (!network)
+ if (!network) {
return;
+ }
switch (state) {
case G_SUPPLICANT_STATE_SCANNING:
@@ -2510,9 +2602,6 @@ static void interface_state(GSupplicantInterface
*interface)
/* though it should be already stopped: */
stop_autoscan(device);
- if (!handle_wps_completion(interface, network, device, wifi))
- break;
-
connman_network_set_connected(network, true);
wifi->disconnect_code = 0;
@@ -2760,9 +2849,6 @@ static void network_added(GSupplicantNetwork
*supplicant_network)
const unsigned char *ssid;
unsigned int ssid_len;
bool wps;
- bool wps_pbc;
- bool wps_ready;
- bool wps_advertizing;
mode = g_supplicant_network_get_mode(supplicant_network);
identifier = g_supplicant_network_get_identifier(supplicant_network);
@@ -2778,10 +2864,6 @@ static void network_added(GSupplicantNetwork
*supplicant_network)
security = g_supplicant_network_get_security(supplicant_network);
group = g_supplicant_network_get_identifier(supplicant_network);
wps = g_supplicant_network_get_wps(supplicant_network);
- wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
- wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
- wps_advertizing = g_supplicant_network_is_wps_advertizing(
- supplicant_network);
if (!wifi)
return;
@@ -2815,16 +2897,6 @@ static void network_added(GSupplicantNetwork
*supplicant_network)
connman_network_set_strength(network,
calculate_strength(supplicant_network));
connman_network_set_bool(network, "WiFi.WPS", wps);
- connman_network_set_bool(network, "WiFi.WPSAdvertising",
- wps_advertizing);
-
- if (wps) {
- /* Is AP advertizing for WPS association?
- * If so, we decide to use WPS by default */
- if (wps_ready && wps_pbc &&
- wps_advertizing)
- connman_network_set_bool(network, "WiFi.UseWPS", true);
- }
connman_network_set_frequency(network,
g_supplicant_network_get_frequency(supplicant_network));
@@ -3009,6 +3081,33 @@ static void apply_peer_services(GSupplicantPeer *peer,
}
}
+static void wps_event(GSupplicantInterface *interface,
+ GSupplicantWpsState state, int error)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ /* Do nothing here for P2P Connections */
+ if (wifi->p2p_connecting)
+ return;
+
+ if (!wifi->wps_running)
+ return;
+
+ switch (state) {
+ case G_SUPPLICANT_WPS_STATE_SUCCESS:
+ DBG("WPS-STA-Event: Success");
+ wps_event_success(interface);
+ break;
+ case G_SUPPLICANT_WPS_STATE_FAIL:
+ DBG("WPS-STA-Event: Fail %d", error);
+ wps_event_fail(interface, error);
+ break;
+ default:
+ DBG("WPS-STA-Event: Not defined");
+ return;
+ }
+}
+
static void peer_found(GSupplicantPeer *peer)
{
GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
@@ -3115,6 +3214,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
@@ -3131,6 +3234,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;
@@ -3198,6 +3303,24 @@ static void assoc_status_code(GSupplicantInterface
*interface, int status_code)
}
}
+static void wps_credential(GSupplicantInterface *interface, const char *group)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+ struct wifi_wps_offered_data *wps_data;
+
+ DBG("");
+
+ wps_data = wps_alloc_offered_data(wifi, group,
+ g_supplicant_interface_get_wps_key(interface));
+ DBG("%s", wps_data->expect_ident);
+
+ connman_technology_wps_state_change_notify(wifi_technology,
+ "cred-received");
+
+ wifi->wps_offered_list = g_slist_append(wifi->wps_offered_list,
+ wps_data);
+}
+
static const GSupplicantCallbacks callbacks = {
.system_ready = system_ready,
.system_killed = system_killed,
@@ -3212,6 +3335,7 @@ static const GSupplicantCallbacks callbacks = {
.network_removed = network_removed,
.network_changed = network_changed,
.network_associated = network_associated,
+ .wps_event = wps_event,
.peer_found = peer_found,
.peer_lost = peer_lost,
.peer_changed = peer_changed,
@@ -3219,6 +3343,7 @@ static const GSupplicantCallbacks callbacks = {
.debug = debug,
.disconnect_reasoncode = disconnect_reasoncode,
.assoc_status_code = assoc_status_code,
+ .wps_credential = wps_credential
};
@@ -3517,6 +3642,502 @@ 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;
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ 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);
+ return;
+ }
+
+ wps_cleanup(wifi);
+ wifi->wps_running = true;
+ wifi->wps_timeout = g_timeout_add(WPS_TIMEOUT_INTERVAL_MSECS,
+ wps_timeout, interface);
+ memset(&wifi->wps_params, 0, sizeof(wifi->wps_params));
+ wifi->wps_params.pin = wps->pin;
+ wifi->wps_params.mode = wps->mode;
+ stop_autoscan(wifi->device);
+}
+
+/*
+ * 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 void cancel_wps_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ if (result < 0)
+ DBG("Error canceling WPS session on %s: %d",
+ g_supplicant_interface_get_ifname(interface), result);
+
+ if (wifi)
+ wps_cleanup(wifi);
+}
+
+static int tech_cancel_wps(struct connman_technology *technology)
+{
+ GList *list;
+ struct wifi_data *wifi;
+ GSupplicantInterface *interface;
+ int err = -EOPNOTSUPP;
+
+ DBG("");
+
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ interface = wifi->interface;
+
+ if (!g_supplicant_interface_support_wps(interface))
+ continue;
+
+ /*
+ * Do not perform WPS Cancel on an interface already connected
+ * to a service or p2p device because it will result in an
+ * undesired disconnection.
+ */
+ if (wifi->connected || wifi->p2p_connected)
+ continue;
+
+ err = g_supplicant_interface_wps_cancel(interface,
+ cancel_wps_callback, NULL);
+ if (err != -EINPROGRESS)
+ break;
+ }
+
+ return err;
+}
+
+static void wps_event_success(GSupplicantInterface *interface)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ wifi->wps_success = true;
+}
+
+static void wps_event_fail(GSupplicantInterface *interface, int error)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+ GSupplicantWPSParams *wps;
+
+ switch (error) {
+ case -ETIMEDOUT:
+ case -EKEYREJECTED:
+ case -EAGAIN:
+ wps_finish(wifi, error);
+ break;
+ case -EACCES:
+ wps_finish(wifi, -ECONNREFUSED);
+ break;
+ default:
+ DBG("Restart WPS");
+ wps = g_try_malloc0(sizeof(*wps));
+ if (!wps) {
+ DBG("No memory");
+ wps_finish(wifi, -ENOMEM);
+ return;
+ }
+ *wps = wifi->wps_params;
+ g_supplicant_interface_wps_start(interface, wps,
+ wps_retry_callback, wps);
+ break;
+ }
+}
+
+static struct wifi_wps_offered_data *wps_alloc_offered_data(
+ struct wifi_data *wifi, const char *group,
+ const char *passphrase)
+{
+ struct wifi_wps_offered_data *wps_data;
+
+ wps_data = g_try_malloc0(sizeof(*wps_data));
+ if (!wps_data)
+ return NULL;
+
+ wps_data->expect_ident =
+ g_strdup_printf("%s_%s_%s",
+ network_driver.name,
+ connman_device_get_ident(wifi->device),
+ group);
+ if (!wps_data->expect_ident)
+ goto fail;
+
+ if (!passphrase)
+ return wps_data;
+
+ if (strlen(passphrase)) {
+ wps_data->passphrase = g_strdup(passphrase);
+ if (!wps_data->passphrase)
+ goto fail;
+ }
+
+ return wps_data;
+
+fail:
+ DBG("No memory");
+ g_free(wps_data->expect_ident);
+ g_free(wps_data->passphrase);
+ g_free(wps_data);
+ return NULL;
+}
+
+static void wps_free_offered_data(struct wifi_wps_offered_data *wps_data)
+{
+ if (wps_data->service)
+ connman_service_unref(wps_data->service);
+ g_free(wps_data->expect_ident);
+ g_free(wps_data->passphrase);
+ g_free(wps_data);
+}
+
+static unsigned int wps_get_accepted_count(struct wifi_data *wifi)
+{
+ unsigned int n = 0;
+ GSList *l;
+
+ for (l = wifi->wps_offered_list; l; l = l->next) {
+ struct wifi_wps_offered_data *data = l->data;
+
+ if (data->service)
+ ++n;
+ }
+
+ return n;
+}
+
+static unsigned int wps_get_offered_count(struct wifi_data *wifi)
+{
+ return g_slist_length(wifi->wps_offered_list);
+}
+
+static bool wps_try_update_services(struct wifi_data *wifi)
+{
+ GSList *l;
+
+ DBG("");
+
+ for (l = wifi->wps_offered_list; l; l = l->next) {
+ struct connman_service *service;
+ struct wifi_wps_offered_data *data = l->data;
+
+ if (data->service)
+ continue;
+ service =
+ __connman_service_lookup_from_ident(data->expect_ident);
+ if (!service)
+ continue;
+ connman_service_ref(service);
+ data->service = service;
+ if (data->passphrase)
+ __connman_service_set_passphrase(service,
+ data->passphrase);
+ __connman_service_force_save(service);
+ DBG("service %p updated", service);
+ }
+
+ return (wps_get_offered_count(wifi) == wps_get_accepted_count(wifi));
+}
+
+static void wps_finish(struct wifi_data *wifi, int error)
+{
+ GSList *list;
+
+ DBG("wifi %p error %d", wifi, error);
+
+ if (!error) {
+ connman_technology_wps_state_change_notify(wifi_technology,
+ "complete");
+ for (list = wifi->wps_offered_list; list; list = list->next) {
+ struct wifi_wps_offered_data *data = list->data;
+
+ if (!data->service)
+ continue;
+ connman_technology_add_wps_offered(wifi_technology,
+ data->expect_ident);
+ }
+ connman_technology_reply_start_sta_wps(wifi_technology, 0);
+ } else {
+ connman_technology_wps_state_change_notify(wifi_technology,
+ "failure");
+ connman_technology_reply_start_sta_wps(wifi_technology, error);
+ }
+
+ wps_cleanup(wifi);
+ if (error)
+ g_supplicant_interface_flushBSS(wifi->interface, 0);
+ reset_autoscan(wifi->device);
+ start_autoscan(wifi->device);
+}
+
+static void wps_cleanup(struct wifi_data *wifi)
+{
+ GSList *list;
+
+ DBG("");
+
+ for (list = wifi->wps_offered_list; list; list = list->next)
+ wps_free_offered_data(list->data);
+ g_slist_free(wifi->wps_offered_list);
+ wifi->wps_offered_list = NULL;
+ wifi->wps_running = false;
+ wifi->wps_success = false;
+ wifi->wps_after_scan = false;
+
+ if (wifi->wps_timeout) {
+ g_source_remove(wifi->wps_timeout);
+ wifi->wps_timeout = 0;
+ }
+
+ memset(&wifi->wps_params, 0, sizeof(wifi->wps_params));
+}
+
+static void wps_scan_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct connman_device *device = user_data;
+ struct wifi_data *wifi = connman_device_get_data(device);
+ bool all_service_accepted;
+
+ DBG("");
+
+ if ((!wifi->wps_running) || (!wifi->wps_after_scan)) {
+ DBG("Operation timed out or canceled");
+ connman_device_unref(device);
+ return;
+ }
+
+ all_service_accepted = wps_try_update_services(wifi);
+ if (all_service_accepted || wps_get_accepted_count(wifi)) {
+ connman_device_unref(device);
+ wps_finish(wifi, 0);
+ } else {
+ int ret;
+
+ DBG("Retry scan");
+ ret = g_supplicant_interface_scan(wifi->interface, NULL,
+ wps_scan_callback, device);
+ if (ret) {
+ DBG("Scan failed");
+ connman_device_unref(device);
+ wps_finish(wifi, -ECONNREFUSED);
+ }
+ }
+}
+
+static gboolean wps_timeout(gpointer data)
+{
+ GSupplicantInterface *interface = data;
+ struct wifi_data *wifi;
+
+ DBG("data %p", data);
+
+ if (!interface)
+ return FALSE;
+
+
+ wifi = g_supplicant_interface_get_data(interface);
+
+ if (wifi->wps_after_scan) {
+ if (wps_get_accepted_count(wifi)) {
+ wps_finish(wifi, 0);
+ return FALSE;
+ }
+ }
+
+ wps_finish(wifi, -ETIMEDOUT);
+ g_supplicant_interface_wps_cancel(interface, NULL, NULL);
+ return FALSE;
+}
+
+static void wps_retry_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ GSupplicantWPSParams *wps = user_data;
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ DBG("");
+
+ if (result) {
+ DBG("Error while restarting WPS Session %d", result);
+
+ if (wps->mode == G_SUPPLICANT_MODE_INFRA)
+ wps_finish(wifi, -EINVAL);
+ return;
+ }
+}
+
static struct connman_technology_driver tech_driver = {
.name = "wifi",
.type = CONNMAN_SERVICE_TYPE_WIFI,
@@ -3524,6 +4145,8 @@ 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,
+ .cancel_wps = tech_cancel_wps,
};
static int wifi_init(void)
diff --git a/src/connman.h b/src/connman.h
index 82e77d37..16ecbb5a 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -54,6 +54,8 @@ DBusMessage *__connman_error_operation_aborted(DBusMessage
*msg);
DBusMessage *__connman_error_operation_timeout(DBusMessage *msg);
DBusMessage *__connman_error_invalid_service(DBusMessage *msg);
DBusMessage *__connman_error_invalid_property(DBusMessage *msg);
+DBusMessage *__connman_error_pin_rejected(DBusMessage *msg);
+DBusMessage *__connman_error_pbc_overlap(DBusMessage *msg);
int __connman_manager_init(void);
void __connman_manager_cleanup(void);
@@ -665,6 +667,8 @@ int __connman_service_init(void);
void __connman_service_cleanup(void);
int __connman_service_load_modifiable(struct connman_service *service);
+void __connman_service_append_struct(struct connman_service *service,
+ DBusMessageIter *iter);
void __connman_service_list_struct(DBusMessageIter *iter);
int __connman_service_compare(const struct connman_service *a,
@@ -843,6 +847,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>
@@ -853,6 +858,7 @@ int __connman_service_iterate_services(service_iterate_cb
cb, void *user_data);
void __connman_service_mark_dirty();
void __connman_service_save(struct connman_service *service);
+void __connman_service_force_save(struct connman_service *service);
#include <connman/notifier.h>
diff --git a/src/error.c b/src/error.c
index 4f24ae25..f0b35bdc 100644
--- a/src/error.c
+++ b/src/error.c
@@ -67,6 +67,10 @@ DBusMessage *__connman_error_failed(DBusMessage *msg, int
errnum)
return __connman_error_in_progress(msg);
case ENOKEY:
return __connman_error_passphrase_required(msg);
+ case EKEYREJECTED:
+ return __connman_error_pin_rejected(msg);
+ case EAGAIN:
+ return __connman_error_pbc_overlap(msg);
}
return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
@@ -185,3 +189,15 @@ DBusMessage *__connman_error_invalid_property(DBusMessage
*msg)
return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
".InvalidProperty", "Invalid property");
}
+
+DBusMessage *__connman_error_pin_rejected(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".PinRejected", "PIN Rejected");
+}
+
+DBusMessage *__connman_error_pbc_overlap(DBusMessage *msg)
+{
+ return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
+ ".PbcOverlap", "PBC Overlap");
+}
diff --git a/src/peer.c b/src/peer.c
index 1b9b80e3..70ffeab4 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/service.c b/src/service.c
index 733c0728..da323d0d 100644
--- a/src/service.c
+++ b/src/service.c
@@ -817,6 +817,15 @@ void __connman_service_save(struct connman_service
*service)
service_save(service);
}
+void __connman_service_force_save(struct connman_service *service)
+{
+ if (!service)
+ return;
+
+ service->new_service = false;
+ service_save(service);
+}
+
static enum connman_service_state combine_state(
enum connman_service_state state_a,
enum connman_service_state state_b)
@@ -2577,6 +2586,18 @@ static void append_struct(gpointer value, gpointer
user_data)
append_struct_service(iter, append_dict_properties, service);
}
+void __connman_service_append_struct(struct connman_service *service,
+ DBusMessageIter *iter)
+{
+ if (!service)
+ return;
+
+ if (!iter)
+ return;
+
+ append_struct(service, iter);
+}
+
void __connman_service_list_struct(DBusMessageIter *iter)
{
g_list_foreach(service_list, append_struct, iter);
--
2.17.1
------------------------------
Subject: Digest Footer
_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman
------------------------------
End of connman Digest, Vol 34, Issue 23
***************************************