X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=plugins%2Fwifi.c;h=5462bf28eb092db9dbe7d24096c9ba90a4e445ad;hb=cd762b0091f6fda81e2a49b2e339abd1a446bc00;hp=40a5913c00940f73ec495cd23f4a4f94694da22e;hpb=016cca4c6be704b306db9551c1f7cb2a91348938;p=connman diff --git a/plugins/wifi.c b/plugins/wifi.c index 40a5913..5462bf2 100644 --- a/plugins/wifi.c +++ b/plugins/wifi.c @@ -23,26 +23,282 @@ #include #endif +#include +#include +#include +#include +#include +#include +#include + +#include + #include #include +#include #include +#include "inet.h" #include "supplicant.h" -static void scan_result(struct connman_element *element, - struct supplicant_network *network) +struct wifi_data { + GSList *list; + gchar *identifier; + gboolean connected; +}; + +static int network_probe(struct connman_element *element) +{ + DBG("element %p name %s", element, element->name); + + return 0; +} + +static void network_remove(struct connman_element *element) { DBG("element %p name %s", element, element->name); +} + +static int network_enable(struct connman_element *element) +{ + char *identifier, *security = NULL, *passphrase = NULL; + unsigned char *ssid; + int ssid_len; + + DBG("element %p name %s", element, element->name); + + if (connman_element_get_static_property(element, + "WiFi.Name", &identifier) == FALSE) + return -EIO; + + if (connman_element_get_static_array_property(element, + "WiFi.SSID", &ssid, &ssid_len) == FALSE) + return -EIO; + + if (element->parent != NULL) { + struct wifi_data *data = connman_element_get_data(element->parent); + + if (data->connected == TRUE) + return -EBUSY; + + if (data != NULL) { + g_free(data->identifier); + data->identifier = g_strdup(identifier); + } + } + + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_WIFI_SECURITY, &security); + + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_WIFI_PASSPHRASE, &passphrase); + + DBG("identifier %s security %s passhprase %s", + identifier, security, passphrase); + + if (__supplicant_connect(element, ssid, ssid_len, + security, passphrase) < 0) + connman_error("Failed to initiate connect"); + + return 0; +} + +static int network_disable(struct connman_element *element) +{ + DBG("element %p name %s", element, element->name); + + connman_element_unregister_children(element); + + __supplicant_disconnect(element); + + return 0; +} + +static struct connman_driver network_driver = { + .name = "wifi-network", + .type = CONNMAN_ELEMENT_TYPE_NETWORK, + .subtype = CONNMAN_ELEMENT_SUBTYPE_WIFI, + .probe = network_probe, + .remove = network_remove, + .enable = network_enable, + .disable = network_disable, +}; + +static struct connman_element *find_element(struct wifi_data *data, + const char *identifier) +{ + GSList *list; + + for (list = data->list; list; list = list->next) { + struct connman_element *element = list->data; + + if (connman_element_match_static_property(element, + "WiFi.Name", &identifier) == TRUE) + return element; + } + + return NULL; +} + +static void state_change(struct connman_element *parent, + enum supplicant_state state) +{ + struct wifi_data *data = connman_element_get_data(parent); + struct connman_element *element; + + DBG("state %d", state); + + if (data->identifier == NULL) + return; + + element = find_element(data, data->identifier); + if (element == NULL) + return; + + if (state == STATE_COMPLETED) { + struct connman_element *dhcp; + + data->connected = TRUE; + + dhcp = connman_element_create(NULL); + + dhcp->type = CONNMAN_ELEMENT_TYPE_DHCP; + dhcp->index = element->index; + + connman_element_register(dhcp, element); + } else if (state == STATE_DISCONNECTED || state == STATE_INACTIVE) + data->connected = FALSE; +} + +static void scan_result(struct connman_element *parent, + struct supplicant_network *network) +{ + struct wifi_data *data = connman_element_get_data(parent); + struct connman_element *element; + gchar *temp; + int i; DBG("network %p identifier %s", network, network->identifier); + + if (data == NULL) + return; + + if (network->identifier == NULL) + return; + + if (network->identifier[0] == '\0') + return; + + temp = g_strdup(network->identifier); + + for (i = 0; i < strlen(temp); i++) { + if (temp[i] == ' ' || temp[i] == '.') + temp[i] = '_'; + else if (temp[i] == '-' || temp[i] == '+') + temp[i] = '_'; + else if (temp[i] == '!' || temp[i] == '?') + temp[i] = '_'; + else if (temp[i] == '(' || temp[i] == ')') + temp[i] = '_'; + else if (g_ascii_isprint(temp[i]) == FALSE) + temp[i] = '_'; + temp[i] = g_ascii_tolower(temp[i]); + } + + element = find_element(data, network->identifier); + if (element == NULL) { + guint8 strength; + + element = connman_element_create(temp); + + element->type = CONNMAN_ELEMENT_TYPE_NETWORK; + element->index = parent->index; + + data->list = g_slist_append(data->list, element); + + connman_element_add_static_property(element, "WiFi.Name", + DBUS_TYPE_STRING, &network->identifier); + + connman_element_add_static_array_property(element, "WiFi.SSID", + DBUS_TYPE_BYTE, &network->ssid, network->ssid_len); + + if (element->wifi.security == NULL) { + const char *security; + + if (network->has_rsn == TRUE) + security = "wpa2"; + else if (network->has_wpa == TRUE) + security = "wpa"; + else if (network->has_wep == TRUE) + security = "wep"; + else + security = "none"; + + element->wifi.security = g_strdup(security); + } + + strength = network->quality; + + connman_element_add_static_property(element, "WiFi.Strength", + DBUS_TYPE_BYTE, &strength); + + //connman_element_add_static_property(element, "WiFi.Noise", + // DBUS_TYPE_INT32, &network->noise); + + DBG("%s (%s) strength %d", network->identifier, + element->wifi.security, strength); + + connman_element_register(element, parent); + } + + g_free(temp); } static struct supplicant_callback wifi_callback = { + .state_change = state_change, .scan_result = scan_result, }; static int wifi_probe(struct connman_element *element) { + struct wifi_data *data; + + DBG("element %p name %s", element, element->name); + + data = g_try_new0(struct wifi_data, 1); + if (data == NULL) + return -ENOMEM; + + data->connected = FALSE; + + connman_element_set_data(element, data); + + return 0; +} + +static void wifi_remove(struct connman_element *element) +{ + struct wifi_data *data = connman_element_get_data(element); + + DBG("element %p name %s", element, element->name); + + connman_element_set_data(element, NULL); + + g_free(data->identifier); + g_free(data); +} + +static int wifi_update(struct connman_element *element) +{ + DBG("element %p name %s", element, element->name); + + __supplicant_scan(element); + + return 0; +} + +static int wifi_enable(struct connman_element *element) +{ int err; DBG("element %p name %s", element, element->name); @@ -56,30 +312,200 @@ static int wifi_probe(struct connman_element *element) return 0; } -static void wifi_remove(struct connman_element *element) +static int wifi_disable(struct connman_element *element) { + struct wifi_data *data = connman_element_get_data(element); + GSList *list; + DBG("element %p name %s", element, element->name); - __supplicant_stop(element); + __supplicant_disconnect(element); + + for (list = data->list; list; list = list->next) { + struct connman_element *network = list->data; + + connman_element_unref(network); + } + + g_slist_free(data->list); + data->list = NULL; + + connman_element_unregister_children(element); + + return 0; } static struct connman_driver wifi_driver = { - .name = "wifi", + .name = "wifi-device", .type = CONNMAN_ELEMENT_TYPE_DEVICE, .subtype = CONNMAN_ELEMENT_SUBTYPE_WIFI, .probe = wifi_probe, .remove = wifi_remove, + .update = wifi_update, + .enable = wifi_enable, + .disable = wifi_disable, +}; + +static GSList *device_list = NULL; + +static void wifi_newlink(unsigned short type, int index, + unsigned flags, unsigned change) +{ + struct connman_element *device; + GSList *list; + gboolean exists = FALSE; + gchar *name; + struct iwreq iwr; + int sk; + + DBG("index %d", index); + + if (type != ARPHRD_ETHER) + return; + + name = inet_index2name(index); + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_ifrn.ifrn_name, name, IFNAMSIZ); + + sk = socket(PF_INET, SOCK_DGRAM, 0); + + if (ioctl(sk, SIOCGIWNAME, &iwr) < 0) { + g_free(name); + close(sk); + return; + } + + close(sk); + + for (list = device_list; list; list = list->next) { + struct connman_element *device = list->data; + + if (device->index == index) { + exists = TRUE; + break; + } + } + + if (exists == TRUE) { + g_free(name); + return; + } + + device = connman_element_create(NULL); + device->type = CONNMAN_ELEMENT_TYPE_DEVICE; + device->subtype = CONNMAN_ELEMENT_SUBTYPE_WIFI; + + device->index = index; + device->name = name; + + connman_element_register(device, NULL); + device_list = g_slist_append(device_list, device); +} + +static void wifi_dellink(unsigned short type, int index, + unsigned flags, unsigned change) +{ + GSList *list; + + DBG("index %d", index); + + for (list = device_list; list; list = list->next) { + struct connman_element *device = list->data; + + if (device->index == index) { + device_list = g_slist_remove(device_list, device); + connman_element_unregister(device); + connman_element_unref(device); + break; + } + } +} + +static struct connman_rtnl wifi_rtnl = { + .name = "wifi", + .newlink = wifi_newlink, + .dellink = wifi_dellink, }; +static void supplicant_connect(DBusConnection *connection, void *user_data) +{ + DBG("connection %p", connection); + + __supplicant_init(connection); + + if (connman_rtnl_register(&wifi_rtnl) < 0) + return; + + connman_rtnl_send_getlink(); +} + +static void supplicant_disconnect(DBusConnection *connection, void *user_data) +{ + GSList *list; + + DBG("connection %p", connection); + + connman_rtnl_unregister(&wifi_rtnl); + + for (list = device_list; list; list = list->next) { + struct connman_element *device = list->data; + + connman_element_unregister(device); + connman_element_unref(device); + } + + g_slist_free(device_list); + device_list = NULL; + + __supplicant_exit(); +} + +static DBusConnection *connection; +static guint watch; + static int wifi_init(void) { - return connman_driver_register(&wifi_driver); + int err; + + connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (connection == NULL) + return -EIO; + + err = connman_driver_register(&network_driver); + if (err < 0) { + dbus_connection_unref(connection); + return err; + } + + err = connman_driver_register(&wifi_driver); + if (err < 0) { + connman_driver_unregister(&network_driver); + dbus_connection_unref(connection); + return err; + } + + watch = g_dbus_add_service_watch(connection, SUPPLICANT_NAME, + supplicant_connect, supplicant_disconnect, NULL, NULL); + + if (g_dbus_check_service(connection, SUPPLICANT_NAME) == TRUE) + supplicant_connect(connection, NULL); + + return 0; } static void wifi_exit(void) { + connman_driver_unregister(&network_driver); connman_driver_unregister(&wifi_driver); + + if (watch > 0) + g_dbus_remove_watch(connection, watch); + + supplicant_disconnect(connection, NULL); + + dbus_connection_unref(connection); } -CONNMAN_PLUGIN_DEFINE("WiFi", "WiFi interface plugin", VERSION, +CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION, wifi_init, wifi_exit)