summaryrefslogtreecommitdiff
path: root/plugins/wifi.c
diff options
context:
space:
mode:
authorTomasz Bursztyka <tomasz.bursztyka@nokia.com>2011-01-26 10:09:35 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2011-01-27 12:13:09 +0100
commit09036724f966b168211af78791d5bd7f56434839 (patch)
tree99cc48eb2f0b5d3842e4ddde28758e511a8958e4 /plugins/wifi.c
parentf55f8c71c75901d48d98f1d754a038eef55baf4f (diff)
downloadconnman-09036724f966b168211af78791d5bd7f56434839.tar.gz
connman-09036724f966b168211af78791d5bd7f56434839.tar.bz2
connman-09036724f966b168211af78791d5bd7f56434839.zip
wifi: WPS support
Diffstat (limited to 'plugins/wifi.c')
-rw-r--r--plugins/wifi.c449
1 files changed, 266 insertions, 183 deletions
diff --git a/plugins/wifi.c b/plugins/wifi.c
index b7685eec..c606c667 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -300,6 +300,192 @@ static void system_killed(void)
connman_device_driver_unregister(&wifi_ng_driver);
}
+static int network_probe(struct connman_network *network)
+{
+ DBG("network %p", network);
+
+ return 0;
+}
+
+static void network_remove(struct connman_network *network)
+{
+ DBG("network %p", network);
+}
+
+static void connect_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ connman_error("%s", __func__);
+}
+
+static GSupplicantSecurity network_security(const char *security)
+{
+ if (g_str_equal(security, "none") == TRUE)
+ return G_SUPPLICANT_SECURITY_NONE;
+ else if (g_str_equal(security, "wep") == TRUE)
+ return G_SUPPLICANT_SECURITY_WEP;
+ else if (g_str_equal(security, "psk") == TRUE)
+ return G_SUPPLICANT_SECURITY_PSK;
+ else if (g_str_equal(security, "wpa") == TRUE)
+ return G_SUPPLICANT_SECURITY_PSK;
+ else if (g_str_equal(security, "rsn") == TRUE)
+ return G_SUPPLICANT_SECURITY_PSK;
+ else if (g_str_equal(security, "ieee8021x") == TRUE)
+ return G_SUPPLICANT_SECURITY_IEEE8021X;
+
+ return G_SUPPLICANT_SECURITY_UNKNOWN;
+}
+
+static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
+{
+ const char *security, *passphrase;
+
+ memset(ssid, 0, sizeof(*ssid));
+ ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
+ &ssid->ssid_len);
+ security = connman_network_get_string(network, "WiFi.Security");
+ ssid->security = network_security(security);
+ passphrase = connman_network_get_string(network,
+ "WiFi.Passphrase");
+ if (passphrase == NULL || strlen(passphrase) == 0)
+ ssid->passphrase = NULL;
+ else
+ ssid->passphrase = passphrase;
+
+ ssid->eap = connman_network_get_string(network, "WiFi.EAP");
+
+ /*
+ * If our private key password is unset,
+ * we use the supplied passphrase. That is needed
+ * for PEAP where 2 passphrases (identity and client
+ * cert may have to be provided.
+ */
+ if (connman_network_get_string(network,
+ "WiFi.PrivateKeyPassphrase") == NULL)
+ connman_network_set_string(network,
+ "WiFi.PrivateKeyPassphrase",
+ ssid->passphrase);
+ /* We must have an identity for both PEAP and TLS */
+ ssid->identity = connman_network_get_string(network, "WiFi.Identity");
+ ssid->ca_cert_path = connman_network_get_string(network,
+ "WiFi.CACertFile");
+ ssid->client_cert_path = connman_network_get_string(network,
+ "WiFi.ClientCertFile");
+ ssid->private_key_path = connman_network_get_string(network,
+ "WiFi.PrivateKeyFile");
+ ssid->private_key_passphrase = connman_network_get_string(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");
+
+}
+
+static int network_connect(struct connman_network *network)
+{
+ struct connman_device *device = connman_network_get_device(network);
+ struct wifi_data *wifi;
+ GSupplicantInterface *interface;
+ GSupplicantSSID *ssid;
+
+ DBG("network %p", network);
+
+ if (device == NULL)
+ return -ENODEV;
+
+ wifi = connman_device_get_data(device);
+ if (wifi == NULL)
+ return -ENODEV;
+
+ ssid = g_try_malloc0(sizeof(GSupplicantSSID));
+ if (ssid == NULL)
+ return -ENOMEM;
+
+ interface = wifi->interface;
+
+ ssid_init(ssid, network);
+
+ if (wifi->disconnecting == TRUE)
+ wifi->pending_network = connman_network_ref(network);
+ else {
+ wifi->network = connman_network_ref(network);
+
+ return g_supplicant_interface_connect(interface, ssid,
+ connect_callback, NULL);
+ }
+
+ return -EINPROGRESS;
+}
+
+static void disconnect_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_data *wifi = user_data;
+
+ if (wifi->network != NULL) {
+ /*
+ * if result < 0 supplican return an error because
+ * the network is not current.
+ * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it
+ * failed, call connman_network_set_connected to report
+ * disconnect is completed.
+ */
+ if (result < 0)
+ connman_network_set_connected(wifi->network, FALSE);
+
+ connman_network_unref(wifi->network);
+ }
+
+ wifi->network = NULL;
+
+ wifi->disconnecting = FALSE;
+
+ if (wifi->pending_network != NULL) {
+ network_connect(wifi->pending_network);
+ connman_network_unref(wifi->pending_network);
+ wifi->pending_network = NULL;
+ }
+
+}
+
+static int network_disconnect(struct connman_network *network)
+{
+ struct connman_device *device = connman_network_get_device(network);
+ struct wifi_data *wifi;
+ int err;
+
+ DBG("network %p", network);
+
+ wifi = connman_device_get_data(device);
+ if (wifi == NULL || wifi->interface == NULL)
+ return -ENODEV;
+
+ connman_network_set_associating(network, FALSE);
+
+ if (wifi->disconnecting == TRUE)
+ return -EALREADY;
+
+ wifi->disconnecting = TRUE;
+
+ err = g_supplicant_interface_disconnect(wifi->interface,
+ disconnect_callback, wifi);
+ if (err < 0)
+ wifi->disconnecting = FALSE;
+
+ return err;
+}
+
+static struct connman_network_driver network_driver = {
+ .name = "wifi",
+ .type = CONNMAN_NETWORK_TYPE_WIFI,
+ .priority = CONNMAN_NETWORK_PRIORITY_LOW,
+ .probe = network_probe,
+ .remove = network_remove,
+ .connect = network_connect,
+ .disconnect = network_disconnect,
+};
+
static void interface_added(GSupplicantInterface *interface)
{
const char *ifname = g_supplicant_interface_get_ifname(interface);
@@ -350,6 +536,73 @@ static connman_bool_t is_idle(struct wifi_data *wifi)
return FALSE;
}
+static connman_bool_t is_idle_wps(GSupplicantInterface *interface,
+ struct wifi_data *wifi)
+{
+ /* First, let's check if WPS processing did not went wrong */
+ if (g_supplicant_interface_get_wps_state(interface) ==
+ G_SUPPLICANT_WPS_STATE_FAIL)
+ return FALSE;
+
+ /* Unlike normal connection, being associated while processing wps
+ * actually means that we are idling. */
+ switch (wifi->state) {
+ case G_SUPPLICANT_STATE_UNKNOWN:
+ case G_SUPPLICANT_STATE_DISCONNECTED:
+ case G_SUPPLICANT_STATE_INACTIVE:
+ case G_SUPPLICANT_STATE_SCANNING:
+ case G_SUPPLICANT_STATE_ASSOCIATED:
+ return TRUE;
+ case G_SUPPLICANT_STATE_AUTHENTICATING:
+ case G_SUPPLICANT_STATE_ASSOCIATING:
+ case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
+ case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
+ case G_SUPPLICANT_STATE_COMPLETED:
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+static connman_bool_t handle_wps_completion(GSupplicantInterface *interface,
+ struct connman_network *network,
+ struct connman_device *device,
+ struct wifi_data *wifi)
+{
+ connman_bool_t wps;
+
+ wps = connman_network_get_bool(network, "WiFi.UseWPS");
+ if (wps == TRUE) {
+ const unsigned char *ssid, *wps_ssid;
+ unsigned int ssid_len, wps_ssid_len;
+ const char *wps_key;
+
+ /* Checking if we got associated with requested
+ * network */
+ ssid = connman_network_get_blob(network, "WiFi.SSID",
+ &ssid_len);
+
+ wps_ssid = g_supplicant_interface_get_wps_ssid(
+ interface, &wps_ssid_len);
+
+ if (wps_ssid == NULL || wps_ssid_len != ssid_len ||
+ memcmp(ssid, wps_ssid, ssid_len) != 0) {
+ connman_network_set_associating(network, FALSE);
+ g_supplicant_interface_disconnect(wifi->interface,
+ disconnect_callback, wifi);
+ return FALSE;
+ }
+
+ wps_key = g_supplicant_interface_get_wps_key(interface);
+ connman_network_set_string(network, "WiFi.Passphrase",
+ wps_key);
+
+ connman_network_set_string(network, "WiFi.PinWPS", NULL);
+ }
+
+ return TRUE;
+}
+
static void interface_state(GSupplicantInterface *interface)
{
struct connman_network *network;
@@ -358,6 +611,7 @@ static void interface_state(GSupplicantInterface *interface)
GSupplicantState state = g_supplicant_interface_get_state(interface);
unsigned char bssid[ETH_ALEN];
unsigned int bssid_len;
+ connman_bool_t wps;
wifi = g_supplicant_interface_get_data(interface);
@@ -382,6 +636,10 @@ static void interface_state(GSupplicantInterface *interface)
break;
case G_SUPPLICANT_STATE_COMPLETED:
+ if (handle_wps_completion(interface, network, device, wifi) ==
+ FALSE)
+ break;
+
/* reset scan trigger and schedule background scan */
connman_device_schedule_scan(device);
@@ -398,6 +656,11 @@ static void interface_state(GSupplicantInterface *interface)
* those ones to FALSE could cancel an association
* in progress.
*/
+ wps = connman_network_get_bool(network, "WiFi.UseWPS");
+ if (wps == TRUE)
+ if (is_idle_wps(interface, wifi) == TRUE)
+ break;
+
if (is_idle(wifi))
break;
connman_network_set_associating(network, FALSE);
@@ -480,6 +743,7 @@ static void network_added(GSupplicantNetwork *supplicant_network)
const char *name, *identifier, *mode, *security, *group;
const unsigned char *ssid;
unsigned int ssid_len;
+ connman_bool_t wps;
DBG("");
@@ -490,6 +754,7 @@ static void network_added(GSupplicantNetwork *supplicant_network)
mode = g_supplicant_network_get_mode(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);
if (wifi == NULL)
return;
@@ -521,6 +786,7 @@ static void network_added(GSupplicantNetwork *supplicant_network)
connman_network_set_string(network, "WiFi.Security", security);
connman_network_set_strength(network,
calculate_strength(supplicant_network));
+ connman_network_set_bool(network, "WiFi.WPS", wps);
connman_network_set_available(network, TRUE);
@@ -565,189 +831,6 @@ static const GSupplicantCallbacks callbacks = {
};
-static int network_probe(struct connman_network *network)
-{
- DBG("network %p", network);
-
- return 0;
-}
-
-static void network_remove(struct connman_network *network)
-{
- DBG("network %p", network);
-}
-
-static void connect_callback(int result, GSupplicantInterface *interface,
- void *user_data)
-{
- connman_error("%s", __func__);
-}
-
-static GSupplicantSecurity network_security(const char *security)
-{
- if (g_str_equal(security, "none") == TRUE)
- return G_SUPPLICANT_SECURITY_NONE;
- else if (g_str_equal(security, "wep") == TRUE)
- return G_SUPPLICANT_SECURITY_WEP;
- else if (g_str_equal(security, "psk") == TRUE)
- return G_SUPPLICANT_SECURITY_PSK;
- else if (g_str_equal(security, "wpa") == TRUE)
- return G_SUPPLICANT_SECURITY_PSK;
- else if (g_str_equal(security, "rsn") == TRUE)
- return G_SUPPLICANT_SECURITY_PSK;
- else if (g_str_equal(security, "ieee8021x") == TRUE)
- return G_SUPPLICANT_SECURITY_IEEE8021X;
-
- return G_SUPPLICANT_SECURITY_UNKNOWN;
-}
-
-static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
-{
- const char *security, *passphrase;
-
- memset(ssid, 0, sizeof(*ssid));
- ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
- &ssid->ssid_len);
- security = connman_network_get_string(network, "WiFi.Security");
- ssid->security = network_security(security);
- passphrase = connman_network_get_string(network,
- "WiFi.Passphrase");
- if (passphrase == NULL || strlen(passphrase) == 0)
- ssid->passphrase = NULL;
- else
- ssid->passphrase = passphrase;
-
- ssid->eap = connman_network_get_string(network, "WiFi.EAP");
-
- /*
- * If our private key password is unset,
- * we use the supplied passphrase. That is needed
- * for PEAP where 2 passphrases (identity and client
- * cert may have to be provided.
- */
- if (connman_network_get_string(network,
- "WiFi.PrivateKeyPassphrase") == NULL)
- connman_network_set_string(network,
- "WiFi.PrivateKeyPassphrase",
- ssid->passphrase);
- /* We must have an identity for both PEAP and TLS */
- ssid->identity = connman_network_get_string(network, "WiFi.Identity");
- ssid->ca_cert_path = connman_network_get_string(network,
- "WiFi.CACertFile");
- ssid->client_cert_path = connman_network_get_string(network,
- "WiFi.ClientCertFile");
- ssid->private_key_path = connman_network_get_string(network,
- "WiFi.PrivateKeyFile");
- ssid->private_key_passphrase = connman_network_get_string(network,
- "WiFi.PrivateKeyPassphrase");
- ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
-
-}
-
-static int network_connect(struct connman_network *network)
-{
- struct connman_device *device = connman_network_get_device(network);
- struct wifi_data *wifi;
- GSupplicantInterface *interface;
- GSupplicantSSID *ssid;
-
- DBG("network %p", network);
-
- if (device == NULL)
- return -ENODEV;
-
- wifi = connman_device_get_data(device);
- if (wifi == NULL)
- return -ENODEV;
-
- ssid = g_try_malloc0(sizeof(GSupplicantSSID));
- if (ssid == NULL)
- return -ENOMEM;
-
- interface = wifi->interface;
-
- ssid_init(ssid, network);
-
- if (wifi->disconnecting == TRUE)
- wifi->pending_network = connman_network_ref(network);
- else {
- wifi->network = connman_network_ref(network);
-
- return g_supplicant_interface_connect(interface, ssid,
- connect_callback, NULL);
- }
-
- return -EINPROGRESS;
-}
-
-static void disconnect_callback(int result, GSupplicantInterface *interface,
- void *user_data)
-{
- struct wifi_data *wifi = user_data;
-
- if (wifi->network != NULL) {
- /*
- * if result < 0 supplican return an error because
- * the network is not current.
- * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it
- * failed, call connman_network_set_connected to report
- * disconnect is completed.
- */
- if (result < 0)
- connman_network_set_connected(wifi->network, FALSE);
-
- connman_network_unref(wifi->network);
- }
-
- wifi->network = NULL;
-
- wifi->disconnecting = FALSE;
-
- if (wifi->pending_network != NULL) {
- network_connect(wifi->pending_network);
- connman_network_unref(wifi->pending_network);
- wifi->pending_network = NULL;
- }
-
-}
-
-static int network_disconnect(struct connman_network *network)
-{
- struct connman_device *device = connman_network_get_device(network);
- struct wifi_data *wifi;
- int err;
-
- DBG("network %p", network);
-
- wifi = connman_device_get_data(device);
- if (wifi == NULL || wifi->interface == NULL)
- return -ENODEV;
-
- connman_network_set_associating(network, FALSE);
-
- if (wifi->disconnecting == TRUE)
- return -EALREADY;
-
- wifi->disconnecting = TRUE;
-
- err = g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, wifi);
- if (err < 0)
- wifi->disconnecting = FALSE;
-
- return err;
-}
-
-static struct connman_network_driver network_driver = {
- .name = "wifi",
- .type = CONNMAN_NETWORK_TYPE_WIFI,
- .priority = CONNMAN_NETWORK_PRIORITY_LOW,
- .probe = network_probe,
- .remove = network_remove,
- .connect = network_connect,
- .disconnect = network_disconnect,
-};
-
static int tech_probe(struct connman_technology *technology)
{
wifi_technology = technology;