diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2011-02-03 00:19:35 +0100 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-02-03 00:19:35 +0100 |
commit | 11a61177bbd78969e7d95cca0d3bd083ab0b1106 (patch) | |
tree | e24161bbc3a33c2e03b033867c85b49fe1c6056c /plugins | |
parent | 962a98a75e42abde7489cd83a33c1313ad1ae621 (diff) | |
download | connman-11a61177bbd78969e7d95cca0d3bd083ab0b1106.tar.gz connman-11a61177bbd78969e7d95cca0d3bd083ab0b1106.tar.bz2 connman-11a61177bbd78969e7d95cca0d3bd083ab0b1106.zip |
wifi: Initial tethering support
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/wifi.c | 195 |
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, }; |