summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2011-02-03 00:19:35 +0100
committerSamuel Ortiz <sameo@linux.intel.com>2011-02-03 00:19:35 +0100
commit11a61177bbd78969e7d95cca0d3bd083ab0b1106 (patch)
treee24161bbc3a33c2e03b033867c85b49fe1c6056c
parent962a98a75e42abde7489cd83a33c1313ad1ae621 (diff)
downloadconnman-11a61177bbd78969e7d95cca0d3bd083ab0b1106.tar.gz
connman-11a61177bbd78969e7d95cca0d3bd083ab0b1106.tar.bz2
connman-11a61177bbd78969e7d95cca0d3bd083ab0b1106.zip
wifi: Initial tethering support
-rw-r--r--plugins/wifi.c195
1 files changed, 194 insertions, 1 deletions
diff --git a/plugins/wifi.c b/plugins/wifi.c
index b7055c3d..23a22209 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -65,6 +65,7 @@ struct wifi_data {
GSupplicantState state;
connman_bool_t connected;
connman_bool_t disconnecting;
+ connman_bool_t tethering;
int index;
unsigned flags;
unsigned int watch;
@@ -150,6 +151,7 @@ static int wifi_probe(struct connman_device *device)
wifi->connected = FALSE;
wifi->disconnecting = FALSE;
+ wifi->tethering = FALSE;
wifi->state = G_SUPPLICANT_STATE_INACTIVE;
connman_device_set_data(device, wifi);
@@ -275,6 +277,9 @@ static int wifi_scan(struct connman_device *device)
DBG("device %p %p", device, wifi->interface);
+ if (wifi->tethering == TRUE)
+ return 0;
+
ret = g_supplicant_interface_scan(wifi->interface, scan_callback,
device);
if (ret == 0)
@@ -513,7 +518,8 @@ static void interface_added(GSupplicantInterface *interface)
if (wifi == NULL)
return;
- DBG("ifname %s driver %s wifi %p", ifname, driver, wifi);
+ DBG("ifname %s driver %s wifi %p tethering %d",
+ ifname, driver, wifi, wifi->tethering);
if (wifi->device == NULL) {
connman_error("WiFi device not set");
@@ -521,6 +527,10 @@ static void interface_added(GSupplicantInterface *interface)
}
connman_device_set_powered(wifi->device, TRUE);
+
+ if (wifi->tethering == TRUE)
+ return;
+
wifi_scan(wifi->device);
}
@@ -703,6 +713,9 @@ static void interface_removed(GSupplicantInterface *interface)
wifi = g_supplicant_interface_get_data(interface);
+ if (wifi != NULL && wifi->tethering == TRUE)
+ return;
+
if (wifi == NULL || wifi->device == NULL) {
connman_error("Wrong wifi pointer");
return;
@@ -854,6 +867,185 @@ static void tech_remove(struct connman_technology *technology)
wifi_technology = NULL;
}
+struct wifi_tethering_info {
+ struct wifi_data *wifi;
+ struct connman_technology *technology;
+ char *ifname;
+ const char *bridge;
+ GSupplicantSSID *ssid;
+};
+
+static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
+{
+ GSupplicantSSID *ap;
+
+ ap = g_try_malloc0(sizeof(GSupplicantSSID));
+ if (ap == NULL)
+ return NULL;
+
+ ap->mode = G_SUPPLICANT_MODE_MASTER;
+ ap->ssid = ssid;
+ ap->ssid_len = strlen(ssid);
+ ap->scan_ssid = 0;
+ ap->freq = 2412;
+
+ if (passphrase == NULL || strlen(passphrase) == 0) {
+ ap->security = G_SUPPLICANT_SECURITY_NONE;
+ ap->passphrase = NULL;
+ } else {
+ ap->security = G_SUPPLICANT_SECURITY_PSK;
+ ap->passphrase = passphrase;
+ }
+
+ return ap;
+}
+
+static void ap_start_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_tethering_info *info = user_data;
+
+ DBG("result %d index %d bridge %s",
+ result, info->wifi->index, info->bridge);
+
+ if (result < 0) {
+ connman_inet_remove_from_bridge(info->wifi->index,
+ info->bridge);
+ connman_technology_tethering_notify(info->technology, FALSE);
+ }
+
+ g_free(info->ifname);
+ g_free(info);
+}
+
+static void ap_create_callback(int result,
+ GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_tethering_info *info = user_data;
+ struct connman_technology *technology;
+
+ DBG("result %d ifname %s", result,
+ g_supplicant_interface_get_ifname(interface));
+
+ if (result < 0) {
+ connman_inet_remove_from_bridge(info->wifi->index,
+ info->bridge);
+ connman_technology_tethering_notify(info->technology, FALSE);
+
+ g_free(info->ifname);
+ g_free(info);
+ return;
+ }
+
+ info->wifi->interface = interface;
+ technology = info->technology;
+ g_supplicant_interface_set_data(interface, info->wifi);
+
+ if (g_supplicant_interface_set_apscan(interface, 2) < 0)
+ connman_error("Failed to set interface ap_scan property");
+
+ g_supplicant_interface_connect(interface, info->ssid,
+ ap_start_callback, info);
+}
+
+static void sta_remove_callback(int result,
+ GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_tethering_info *info = user_data;
+ const char *driver = connman_option_get_string("wifi");
+
+ DBG("ifname %s result %d ", info->ifname, result);
+
+ if (result < 0) {
+ info->wifi->tethering = TRUE;
+
+ g_free(info->ifname);
+ g_free(info);
+ return;
+ }
+
+ info->wifi->interface = NULL;
+
+ connman_technology_tethering_notify(info->technology, TRUE);
+ connman_inet_add_to_bridge(info->wifi->index, info->bridge);
+
+ g_supplicant_interface_create(info->ifname, driver, info->bridge,
+ ap_create_callback,
+ info);
+}
+
+static int tech_set_tethering(struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+ const char *bridge, connman_bool_t enabled)
+{
+ GList *list;
+ GSupplicantInterface *interface;
+ struct wifi_data *wifi;
+ struct wifi_tethering_info *info;
+ const char *ifname;
+ unsigned int mode;
+
+ DBG("");
+
+ if (enabled == FALSE) {
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ if (wifi->tethering == TRUE)
+ wifi->tethering = FALSE;
+ }
+
+ connman_technology_tethering_notify(technology, FALSE);
+
+ return 0;
+ }
+
+ for (list = iface_list; list; list = list->next) {
+ wifi = list->data;
+
+ interface = wifi->interface;
+
+ if (interface == NULL)
+ continue;
+
+ ifname = g_supplicant_interface_get_ifname(wifi->interface);
+
+ mode = g_supplicant_interface_get_mode(interface);
+ if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
+ DBG("ifname does not support AP mode");
+ continue;
+ }
+
+ info = g_try_malloc0(sizeof(struct wifi_tethering_info));
+ if (info == NULL)
+ return -ENOMEM;
+
+ info->wifi = wifi;
+ info->technology = technology;
+ info->bridge = bridge;
+ info->ssid = ssid_ap_init(identifier, passphrase);
+ if (info->ssid == NULL) {
+ g_free(info);
+ continue;
+ }
+ info->ifname = g_strdup(ifname);
+ if (info->ifname == NULL) {
+ g_free(info);
+ continue;
+ }
+
+ info->wifi->tethering = TRUE;
+
+ return g_supplicant_interface_remove(interface,
+ sta_remove_callback,
+ info);
+ }
+
+ return 0;
+}
+
static void regdom_callback(void *user_data)
{
char *alpha2 = user_data;
@@ -876,6 +1068,7 @@ static struct connman_technology_driver tech_driver = {
.type = CONNMAN_SERVICE_TYPE_WIFI,
.probe = tech_probe,
.remove = tech_remove,
+ .set_tethering = tech_set_tethering,
.set_regdom = tech_set_regdom,
};