X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=plugins%2Fwifi.c;h=a434d5b6c0f0cbd7e734aebd59fcb1f3328471df;hb=a48fa9fdffe415e9a6f703776b5db795e242ac23;hp=c471accf5fc549dc8bce0adac70c577b2bbf156d;hpb=5d9d3391d8d6f853b47c208499e8b760170120ae;p=platform%2Fupstream%2Fconnman.git diff --git a/plugins/wifi.c b/plugins/wifi.c old mode 100755 new mode 100644 index c471acc..a434d5b --- a/plugins/wifi.c +++ b/plugins/wifi.c @@ -72,7 +72,11 @@ #define P2P_LISTEN_INTERVAL 2000 #define ASSOC_STATUS_NO_CLIENT 17 +#if defined TIZEN_EXT +#define LOAD_SHAPING_MAX_RETRIES 7 +#else #define LOAD_SHAPING_MAX_RETRIES 3 +#endif #if defined TIZEN_EXT #define WIFI_EAP_FAST_PAC_FILE "/var/lib/wifi/wifi.pac" /* path of Pac file for EAP-FAST */ @@ -160,9 +164,14 @@ struct wifi_data { int assoc_retry_count; struct connman_network *scan_pending_network; bool allow_full_scan; + unsigned int automaxspeed_timeout; #endif int disconnect_code; int assoc_code; +#if defined TIZEN_EXT_WIFI_MESH + bool mesh_interface; + struct wifi_mesh_info *mesh_info; +#endif }; #if defined TIZEN_EXT @@ -174,6 +183,8 @@ struct wifi_data { static gboolean wifi_first_scan = false; static gboolean found_with_first_scan = false; static gboolean is_wifi_notifier_registered = false; +static GHashTable *failed_bssids = NULL; +static unsigned char buff_bssid[WIFI_BSSID_LEN_MAX] = { 0, }; #endif @@ -347,6 +358,506 @@ static void add_pending_wifi_device(struct wifi_data *wifi) pending_wifi_device = g_list_append(pending_wifi_device, wifi); } +#if defined TIZEN_EXT_WIFI_MESH +struct wifi_mesh_info { + struct wifi_data *wifi; + GSupplicantInterface *interface; + struct connman_mesh *mesh; + char *parent_ifname; + char *ifname; + char *identifier; + int index; +}; + +struct mesh_change_peer_status_info { + char *peer_address; + enum connman_mesh_peer_status peer_status; + mesh_change_peer_status_cb_t callback; + void *user_data; +}; + +static struct connman_technology_driver mesh_tech_driver = { + .name = "mesh", + .type = CONNMAN_SERVICE_TYPE_MESH, +}; + +static void mesh_interface_create_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct wifi_mesh_info *mesh_info = user_data; + struct wifi_data *wifi; + bool success = false; + + DBG("result %d ifname %s, mesh_info %p", result, + g_supplicant_interface_get_ifname(interface), + mesh_info); + + if (result < 0 || !mesh_info) + goto done; + + wifi = mesh_info->wifi; + + mesh_info->interface = interface; + mesh_info->identifier = connman_inet_ifaddr(mesh_info->ifname); + mesh_info->index = connman_inet_ifindex(mesh_info->ifname); + DBG("Mesh Interface identifier %s", mesh_info->identifier); + wifi->mesh_interface = true; + wifi->mesh_info = mesh_info; + g_supplicant_interface_set_data(interface, wifi); + success = true; + +done: + connman_mesh_notify_interface_create(success); +} + +static int add_mesh_interface(const char *ifname, const char *parent_ifname) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + const char *wifi_ifname; + bool parent_found = false; + const char *driver = "nl80211"; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (!g_supplicant_interface_has_mesh(wifi->interface)) + continue; + + wifi_ifname = g_supplicant_interface_get_ifname(wifi->interface); + if (!wifi_ifname) + continue; + + if (!g_strcmp0(wifi_ifname, parent_ifname)) { + parent_found = true; + break; + } + } + + if (!parent_found) { + DBG("Parent interface %s doesn't exist", parent_ifname); + return -ENODEV; + } + + mesh_info = g_try_malloc0(sizeof(struct wifi_mesh_info)); + if (!mesh_info) + return -ENOMEM; + + mesh_info->wifi = wifi; + mesh_info->ifname = g_strdup(ifname); + mesh_info->parent_ifname = g_strdup(parent_ifname); + + g_supplicant_mesh_interface_create(ifname, driver, NULL, parent_ifname, + mesh_interface_create_callback, mesh_info); + return -EINPROGRESS; +} + +static void mesh_interface_remove_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct wifi_data *wifi = user_data; + struct wifi_mesh_info *mesh_info = wifi->mesh_info; + bool success = false; + + DBG("result %d mesh_info %p", result, mesh_info); + + if (result < 0 || !mesh_info) + goto done; + + mesh_info->interface = NULL; + g_free(mesh_info->parent_ifname); + g_free(mesh_info->ifname); + g_free(mesh_info->identifier); + g_free(mesh_info); + wifi->mesh_interface = false; + wifi->mesh_info = NULL; + success = true; + +done: + connman_mesh_notify_interface_remove(success); +} + +static int remove_mesh_interface(const char *ifname) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + int ret; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface %s doesn't exist", ifname); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + ret = g_supplicant_interface_remove(mesh_info->interface, + mesh_interface_remove_callback, wifi); + if (ret < 0) + return ret; + + return -EINPROGRESS; +} + +static void mesh_disconnect_callback(int result, + GSupplicantInterface *interface, void *user_data) +{ + struct connman_mesh *mesh = user_data; + + DBG("result %d interface %p mesh %p", result, interface, mesh); +} + +static int mesh_peer_disconnect(struct connman_mesh *mesh) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + return g_supplicant_interface_disconnect(interface, + mesh_disconnect_callback, mesh); +} + +static void mesh_connect_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_mesh *mesh = user_data; + DBG("mesh %p result %d", mesh, result); + + if (result < 0) + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE); + else + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_ASSOCIATION); +} + +static GSupplicantSecurity mesh_network_security(const char *security) +{ + if (g_str_equal(security, "none")) + return G_SUPPLICANT_SECURITY_NONE; + else if (g_str_equal(security, "sae")) + return G_SUPPLICANT_SECURITY_SAE; + + return G_SUPPLICANT_SECURITY_UNKNOWN; +} + +static void mesh_ssid_init(GSupplicantSSID *ssid, struct connman_mesh *mesh) +{ + const char *name; + const char *security; + + if (ssid->ssid) + g_free(ssid->ssid); + + memset(ssid, 0, sizeof(*ssid)); + ssid->mode = G_SUPPLICANT_MODE_MESH; + + security = connman_mesh_get_security(mesh); + ssid->security = mesh_network_security(security); + + if (ssid->security == G_SUPPLICANT_SECURITY_SAE) + ssid->passphrase = connman_mesh_get_passphrase(mesh); + + ssid->freq = connman_mesh_get_frequency(mesh); + name = connman_mesh_get_name(mesh); + if (name) { + ssid->ssid_len = strlen(name); + ssid->ssid = g_malloc0(ssid->ssid_len + 1); + memcpy(ssid->ssid, name, ssid->ssid_len); + ssid->scan_ssid = 1; + } +} + +static int mesh_peer_connect(struct connman_mesh *mesh) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + GSupplicantSSID *ssid; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + + ssid = g_try_malloc0(sizeof(GSupplicantSSID)); + if (!ssid) + return -ENOMEM; + + mesh_info->mesh = mesh; + + mesh_ssid_init(ssid, mesh); + return g_supplicant_interface_connect(interface, ssid, + mesh_connect_callback, mesh); +} + +static void mesh_peer_change_status_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct mesh_change_peer_status_info *data = user_data; + + DBG("result %d Peer Status %d", result, data->peer_status); + + if (result == 0 && data->peer_status == CONNMAN_MESH_PEER_REMOVE) { + /* WLAN_REASON_MESH_PEERING_CANCELLED = 52 */ + connman_mesh_remove_connected_peer(data->peer_address, 52); + } + + if (data->callback) + data->callback(result, data->user_data); + + g_free(data->peer_address); + g_free(data); + return; +} + +static int mesh_change_peer_status(const char *peer_address, + enum connman_mesh_peer_status status, + mesh_change_peer_status_cb_t callback, void *user_data) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + struct mesh_change_peer_status_info *data; + const char *method; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + + switch (status) { + case CONNMAN_MESH_PEER_ADD: + method = "MeshPeerAdd"; + break; + case CONNMAN_MESH_PEER_REMOVE: + method = "MeshPeerRemove"; + break; + default: + DBG("Invalid method"); + return -EINVAL; + } + + data = g_try_malloc0(sizeof(struct mesh_change_peer_status_info)); + if (data == NULL) { + DBG("Memory allocation failed"); + return -ENOMEM; + } + + data->peer_address = g_strdup(peer_address); + data->peer_status = status; + data->callback = callback; + data->user_data = user_data; + + return g_supplicant_interface_mesh_peer_change_status(interface, + mesh_peer_change_status_callback, peer_address, method, + data); +} + +static struct connman_mesh_driver mesh_driver = { + .add_interface = add_mesh_interface, + .remove_interface = remove_mesh_interface, + .connect = mesh_peer_connect, + .disconnect = mesh_peer_disconnect, + .change_peer_status = mesh_change_peer_status, +}; + +static void mesh_support(GSupplicantInterface *interface) +{ + DBG(""); + + if (!g_supplicant_interface_has_mesh(interface)) + return; + + if (connman_technology_driver_register(&mesh_tech_driver) < 0) { + DBG("Could not register Mesh technology driver"); + return; + } + + connman_mesh_driver_register(&mesh_driver); +} + +static void check_mesh_technology(void) +{ + bool mesh_exists = false; + GList *list; + + for (list = iface_list; list; list = list->next) { + struct wifi_data *w = list->data; + + if (w->interface && + g_supplicant_interface_has_mesh(w->interface)) + mesh_exists = true; + } + + if (!mesh_exists) { + connman_technology_driver_unregister(&mesh_tech_driver); + connman_mesh_driver_unregister(&mesh_driver); + } +} + +static void mesh_group_started(GSupplicantInterface *interface) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + struct connman_mesh *mesh; + const unsigned char *ssid; + unsigned int ssid_len; + char name[33]; + + ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len); + memcpy(name, ssid, ssid_len); + name[ssid_len] = '\0'; + DBG("name %s", name); + wifi = g_supplicant_interface_get_data(interface); + DBG("wifi %p", wifi); + + if (!wifi) + return; + + mesh_info = wifi->mesh_info; + if (!mesh_info) + return; + + mesh = mesh_info->mesh; + if (!mesh) + return; + + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_CONFIGURATION); +} + +static void mesh_group_removed(GSupplicantInterface *interface) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + struct connman_mesh *mesh; + const unsigned char *ssid; + unsigned int ssid_len; + int disconnect_reason; + char name[33]; + + ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len); + memcpy(name, ssid, ssid_len); + name[ssid_len] = '\0'; + DBG("name %s", name); + + disconnect_reason = g_supplicant_mesh_get_disconnect_reason(interface); + DBG("Disconnect Reason %d", disconnect_reason); + + wifi = g_supplicant_interface_get_data(interface); + DBG("wifi %p", wifi); + + if (!wifi) + return; + + mesh_info = wifi->mesh_info; + if (!mesh_info) + return; + + mesh = connman_get_connected_mesh_from_name(name); + if (!mesh) { + DBG("%s is not connected", name); + mesh = connman_get_connecting_mesh_from_name(name); + if (!mesh) { + DBG("%s is not connecting", name); + return; + } + } + + connman_mesh_peer_set_disconnect_reason(mesh, disconnect_reason); + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_DISCONNECT); +} + +static void mesh_peer_connected(GSupplicantMeshPeer *mesh_peer) +{ + const char *peer_address; + + peer_address = g_supplicant_mesh_peer_get_address(mesh_peer); + + if (!peer_address) + return; + + DBG("Peer %s connected", peer_address); + connman_mesh_add_connected_peer(peer_address); +} + +static void mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer) +{ + const char *peer_address; + int reason; + + peer_address = g_supplicant_mesh_peer_get_address(mesh_peer); + + if (!peer_address) + return; + + reason = g_supplicant_mesh_peer_get_disconnect_reason(mesh_peer); + + DBG("Peer %s disconnected with reason %d", peer_address, reason); + connman_mesh_remove_connected_peer(peer_address, reason); +} +#endif + static struct wifi_data *get_pending_wifi_data(const char *ifname) { GList *list; @@ -1034,6 +1545,9 @@ static void wifi_remove(struct connman_device *device) iface_list = g_list_remove(iface_list, wifi); check_p2p_technology(); +#if defined TIZEN_EXT_WIFI_MESH + check_mesh_technology(); +#endif remove_pending_wifi_device(wifi); @@ -1045,6 +1559,13 @@ static void wifi_remove(struct connman_device *device) if (wifi->p2p_connection_timeout) g_source_remove(wifi->p2p_connection_timeout); +#if defined TIZEN_EXT + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + } +#endif + remove_networks(device, wifi); remove_peers(wifi); @@ -1775,6 +2296,13 @@ static int wifi_disable(struct connman_device *device) connman_device_unref(wifi->device); } +#if defined TIZEN_EXT + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + } +#endif + /* In case of a user scan, device is still referenced */ if (connman_device_get_scanning(device)) { connman_device_set_scanning(device, @@ -2094,7 +2622,7 @@ static int wifi_specific_scan(enum connman_service_type type, } memcpy(scan_ssid->ssid, ssid, (ssid_len + 1)); - DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); + /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */ scan_ssid->ssid_len = ssid_len; scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); count++; @@ -2129,65 +2657,218 @@ static int wifi_specific_scan(enum connman_service_type type, } scan_params->num_freqs = count; - } else if (scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { /* SSID & Frequency mixed scan */ - int freq_count, ap_count; - scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); - if (!scan_params) { - DBG("Failed to allocate memory."); - return -ENOMEM; - } + } else if (scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { /* SSID & Frequency mixed scan */ + int freq_count, ap_count; + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) { + DBG("Failed to allocate memory."); + return -ENOMEM; + } + + guint size = g_slist_length(specific_scan_list); + + scan_params->freqs = g_try_new0(uint16_t, size/2); + if (!scan_params->freqs) { + DBG("Failed to allocate memory."); + g_free(scan_params); + return -ENOMEM; + } + + ap_count = freq_count = 0; + for (list = specific_scan_list; list; list = list->next) { + if (((connman_multi_scan_ap_s *)list->data)->flag == true) { /** ssid */ + ssid = ((connman_multi_scan_ap_s *)list->data)->str; + int ssid_len = strlen(ssid); + + scan_ssid = g_try_new0(struct scan_ssid, 1); + if (!scan_ssid) { + DBG("Failed to allocate memory."); + g_supplicant_free_scan_params(scan_params); + return -ENOMEM; + } + + memcpy(scan_ssid->ssid, ssid, (ssid_len + 1)); + /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */ + scan_ssid->ssid_len = ssid_len; + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + ap_count++; + + } else { /* freq */ + freq = atoi(((connman_multi_scan_ap_s *)list->data)->str); + scan_params->freqs[freq_count] = freq; + DBG("scan_params->freqs[%d]: %d", freq_count, scan_params->freqs[freq_count]); + freq_count++; + } + } + scan_params->num_ssids = ap_count; + scan_params->num_freqs = freq_count; + } else { + DBG("Invalid scan"); + return -EINVAL; + } + + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(wifi->interface, scan_params, + specific_scan_callback, device); + + if (ret == 0) { + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI, true); + } else { + g_supplicant_free_scan_params(scan_params); + connman_device_unref(device); + } + + return ret; +} +#endif + +#if defined TIZEN_EXT_WIFI_MESH +static void mesh_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 scanning; + + DBG("result %d wifi %p", result, wifi); + + scanning = connman_device_get_scanning(device); + if (scanning) + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, false); + + if (scanning) + connman_device_unref(device); +} + +static int mesh_scan(struct connman_device *device) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + int ret; + + DBG(""); + + wifi = connman_device_get_data(device); + + if (!wifi->mesh_interface) + return -ENOTSUP; + + mesh_info = wifi->mesh_info; + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(mesh_info->interface, NULL, + mesh_scan_callback, device); + if (ret) + connman_device_unref(device); + else + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, true); + + return ret; +} + +static void abort_scan_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_device *device = user_data; + struct wifi_data *wifi = connman_device_get_data(device); + + DBG("result %d wifi %p", result, wifi); + + __connman_technology_notify_abort_scan(CONNMAN_SERVICE_TYPE_MESH, result); +} + +static int mesh_abort_scan(enum connman_service_type type, + struct connman_device *device) +{ + struct wifi_data *wifi = connman_device_get_data(device); + struct wifi_mesh_info *mesh_info; + bool scanning; + int ret; + + if (!wifi || !wifi->mesh_interface) + return -ENODEV; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; + + mesh_info = wifi->mesh_info; + + scanning = connman_device_get_scanning(device); + if (!scanning) + return -EEXIST; + + ret = g_supplicant_interface_abort_scan(mesh_info->interface, + abort_scan_callback, device); + + return ret; +} + +static int mesh_specific_scan(enum connman_service_type type, + struct connman_device *device, const char *ssid, + unsigned int freq, void *user_data) +{ + struct wifi_data *wifi = connman_device_get_data(device); + GSupplicantScanParams *scan_params = NULL; + struct wifi_mesh_info *mesh_info; + struct scan_ssid *scan_ssid; + bool scanning; + int ret; + + if (!wifi || !wifi->mesh_interface) + return -ENODEV; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; - guint size = g_slist_length(specific_scan_list); + if (wifi->p2p_device) + return 0; - scan_params->freqs = g_try_new0(uint16_t, size/2); - if (!scan_params->freqs) { - DBG("Failed to allocate memory."); - g_free(scan_params); - return -ENOMEM; - } + mesh_info = wifi->mesh_info; - ap_count = freq_count = 0; - for (list = specific_scan_list; list; list = list->next) { - if (((connman_multi_scan_ap_s *)list->data)->flag == true) { /** ssid */ - ssid = ((connman_multi_scan_ap_s *)list->data)->str; - int ssid_len = strlen(ssid); + scanning = connman_device_get_scanning(device); + if (scanning) + return -EALREADY; - scan_ssid = g_try_new0(struct scan_ssid, 1); - if (!scan_ssid) { - DBG("Failed to allocate memory."); - g_supplicant_free_scan_params(scan_params); - return -ENOMEM; - } + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) + return -ENOMEM; - memcpy(scan_ssid->ssid, ssid, (ssid_len + 1)); - DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); - scan_ssid->ssid_len = ssid_len; - scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); - ap_count++; + scan_ssid = g_try_new(struct scan_ssid, 1); + if (!scan_ssid) { + g_free(scan_params); + return -ENOMEM; + } - } else { /* freq */ - freq = atoi(((connman_multi_scan_ap_s *)list->data)->str); - scan_params->freqs[freq_count] = freq; - DBG("scan_params->freqs[%d]: %d", freq_count, scan_params->freqs[freq_count]); - freq_count++; - } - } - scan_params->num_ssids = ap_count; - scan_params->num_freqs = freq_count; - } else { - DBG("Invalid scan"); - return -EINVAL; + scan_ssid->ssid_len = strlen(ssid); + memcpy(scan_ssid->ssid, ssid, scan_ssid->ssid_len); + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + scan_params->num_ssids = 1; + + scan_params->freqs = g_try_new(uint16_t, 1); + if (!scan_params->freqs) { + g_slist_free_full(scan_params->ssids, g_free); + g_free(scan_params); + return -ENOMEM; } + scan_params->freqs[0] = freq; + scan_params->num_freqs = 1; + reset_autoscan(device); connman_device_ref(device); - ret = g_supplicant_interface_scan(wifi->interface, scan_params, - specific_scan_callback, device); + ret = g_supplicant_interface_scan(mesh_info->interface, scan_params, + mesh_scan_callback, device); if (ret == 0) { connman_device_set_scanning(device, - CONNMAN_SERVICE_TYPE_WIFI, true); + CONNMAN_SERVICE_TYPE_MESH, true); } else { g_supplicant_free_scan_params(scan_params); connman_device_unref(device); @@ -2228,6 +2909,11 @@ static int wifi_scan(enum connman_service_type type, if (type == CONNMAN_SERVICE_TYPE_P2P) return p2p_find(device); +#if defined TIZEN_EXT_WIFI_MESH + if (type == CONNMAN_SERVICE_TYPE_MESH) + return mesh_scan(device); +#endif + DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, ssid); scanning = connman_device_get_scanning(device); @@ -2379,6 +3065,10 @@ static struct connman_device_driver wifi_ng_driver = { #if defined TIZEN_EXT .specific_scan = wifi_specific_scan, #endif +#if defined TIZEN_EXT_WIFI_MESH + .abort_scan = mesh_abort_scan, + .mesh_specific_scan = mesh_specific_scan, +#endif }; static void system_ready(void) @@ -2486,6 +3176,8 @@ static GSupplicantSecurity network_security(const char *security) return G_SUPPLICANT_SECURITY_FT_PSK; else if (g_str_equal(security, "ft_ieee8021x") == TRUE) return G_SUPPLICANT_SECURITY_FT_IEEE8021X; + else if (g_str_equal(security, "sae")) + return G_SUPPLICANT_SECURITY_SAE; #endif return G_SUPPLICANT_SECURITY_UNKNOWN; @@ -2509,14 +3201,31 @@ static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security) static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) { const char *security; +#if defined TIZEN_EXT + const void *ssid_data; +#endif memset(ssid, 0, sizeof(*ssid)); ssid->mode = G_SUPPLICANT_MODE_INFRA; +#if defined TIZEN_EXT + ssid_data = connman_network_get_blob(network, "WiFi.SSID", + &ssid->ssid_len); + ssid->ssid = g_try_malloc0(ssid->ssid_len); + + if (!ssid->ssid) + ssid->ssid_len = 0; + else + memcpy(ssid->ssid, ssid_data, ssid->ssid_len); +#else ssid->ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid->ssid_len); +#endif ssid->scan_ssid = 1; security = connman_network_get_string(network, "WiFi.Security"); ssid->security = network_security(security); +#if defined TIZEN_EXT + ssid->ieee80211w = 1; +#endif ssid->passphrase = connman_network_get_string(network, "WiFi.Passphrase"); ssid->eap = connman_network_get_string(network, "WiFi.EAP"); @@ -2563,15 +3272,6 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS"); #if defined TIZEN_EXT - ssid->bssid = connman_network_get_bssid(network); - - ssid->eap_keymgmt = network_eap_keymgmt( - connman_network_get_string(network, "WiFi.KeymgmtType")); - ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1"); - - if(g_strcmp0(ssid->eap, "fast") == 0) - ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE); - if (set_connman_bssid(CHECK_BSSID, NULL) == 6) { ssid->bssid_for_connect_len = 6; set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect); @@ -2582,6 +3282,59 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) } else { ssid->freq = connman_network_get_frequency(network); } + + GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network); + if (bssid_list && g_slist_length(bssid_list) > 1) { + + /* If there are more than one bssid, + * the user-specified bssid is tried only once at the beginning. + * After that, the bssids in the list are tried in order. + */ + if (set_connman_bssid(CHECK_BSSID, NULL) == 6) { + set_connman_bssid(RESET_BSSID, NULL); + goto done; + } + + GSList *list; + char buff[MAC_ADDRESS_LENGTH]; + for (list = bssid_list; list; list = list->next) { + struct connman_bssids * bssids = (struct connman_bssids *)list->data; + + g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x", + bssids->bssid[0], bssids->bssid[1], bssids->bssid[2], + bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]); + buff[MAC_ADDRESS_LENGTH - 1] = '\0'; + + gchar *curr_bssid = g_strdup((const gchar *)buff); + + if (g_hash_table_contains(failed_bssids, curr_bssid)) { + DBG("bssid match, try next bssid"); + g_free(curr_bssid); + continue; + } else { + g_hash_table_add(failed_bssids, curr_bssid); + + memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX); + ssid->bssid = buff_bssid; + ssid->freq = (unsigned int)bssids->frequency; + break; + } + } + + if (!list) { + ssid->bssid = connman_network_get_bssid(network); + g_hash_table_remove_all(failed_bssids); + } + } else + ssid->bssid = connman_network_get_bssid(network); + +done: + ssid->eap_keymgmt = network_eap_keymgmt( + connman_network_get_string(network, "WiFi.KeymgmtType")); + ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1"); + + if(g_strcmp0(ssid->eap, "fast") == 0) + ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE); #endif if (connman_setting_get_bool("BackgroundScanning")) @@ -2614,6 +3367,9 @@ static int network_connect(struct connman_network *network) if (wifi->disconnecting) { wifi->pending_network = network; +#if defined TIZEN_EXT + g_free(ssid->ssid); +#endif g_free(ssid); } else { wifi->network = connman_network_ref(network); @@ -2740,6 +3496,130 @@ static int network_disconnect(struct connman_network *network) return err; } +#if defined TIZEN_EXT +static void set_connection_mode(struct connman_network *network, + int linkspeed) +{ + ieee80211_modes_e phy_mode; + connection_mode_e conn_mode; + + phy_mode = connman_network_get_phy_mode(network); + switch (phy_mode) { + case IEEE80211_MODE_B: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_BG: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else if (linkspeed > 11 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211G; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_BGN: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else if (linkspeed > 11 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211G; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_A: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_AN: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_ANAC: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else if (linkspeed > 450 && linkspeed <= 1300) + conn_mode = CONNECTION_MODE_IEEE80211AC; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + default: + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + break; + } + + DBG("connection mode(%d)", conn_mode); + connman_network_set_connection_mode(network, conn_mode); +} + +static void signalpoll_callback(int result, int maxspeed, void *user_data) +{ + struct connman_network *network = user_data; + + if (result != 0) { + DBG("Failed to get maxspeed from signalpoll !"); + return; + } + + DBG("maxspeed = %d", maxspeed); + if (network) { + connman_network_set_maxspeed(network, maxspeed); + set_connection_mode(network, maxspeed); + } +} + +static int network_signalpoll(struct wifi_data *wifi) +{ + GSupplicantInterface *interface; + struct connman_network *network; + + if (!wifi || !wifi->network) + return -ENODEV; + + interface = wifi->interface; + network = wifi->network; + + DBG("network %p", network); + + return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network); +} + +static gboolean autosignalpoll_timeout(gpointer data) +{ + struct wifi_data *wifi = data; + + if (!wifi || !wifi->automaxspeed_timeout) { + DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!"); + return FALSE; + } + + int ret = network_signalpoll(wifi); + if (ret < 0) { + DBG("Fail to get max speed !!"); + wifi->automaxspeed_timeout = 0; + return FALSE; + } + + return TRUE; +} +#endif + static struct connman_network_driver network_driver = { .name = "wifi", .type = CONNMAN_NETWORK_TYPE_WIFI, @@ -2754,6 +3634,10 @@ static void interface_added(GSupplicantInterface *interface) { const char *ifname = g_supplicant_interface_get_ifname(interface); const char *driver = g_supplicant_interface_get_driver(interface); +#if defined TIZEN_EXT + bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface); +#endif + struct wifi_data *wifi; wifi = g_supplicant_interface_get_data(interface); @@ -2777,6 +3661,12 @@ static void interface_added(GSupplicantInterface *interface) } connman_device_set_powered(wifi->device, true); +#if defined TIZEN_EXT + connman_techonology_wifi_set_5ghz_supported(wifi_technology, is_5_0_ghz_supported); + /* Max number of SSIDs supported by wlan chipset that can be scanned */ + int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface); + connman_techonology_set_max_scan_ssids(wifi_technology, max_scan_ssids); +#endif } static bool is_idle(struct wifi_data *wifi) @@ -2908,7 +3798,11 @@ static bool handle_assoc_status_code(GSupplicantInterface *interface, struct wifi_data *wifi) { if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING && +#if defined TIZEN_EXT + wifi->assoc_code > 0 && +#else wifi->assoc_code == ASSOC_STATUS_NO_CLIENT && +#endif wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) { wifi->load_shaping_retries ++; return TRUE; @@ -3082,6 +3976,17 @@ static void interface_state(GSupplicantInterface *interface) CONNMAN_SERVICE_TYPE_WIFI, false); connman_device_unref(device); } + + if (!wifi->automaxspeed_timeout) { + DBG("Going to start signalpoll timer!!"); + int ret = network_signalpoll(wifi); + if (ret < 0) + DBG("Fail to get max speed !!"); + else + wifi->automaxspeed_timeout = g_timeout_add_seconds(30, autosignalpoll_timeout, wifi); + } + + g_hash_table_remove_all(failed_bssids); #else /* though it should be already stopped: */ stop_autoscan(device); @@ -3098,6 +4003,15 @@ static void interface_state(GSupplicantInterface *interface) break; case G_SUPPLICANT_STATE_DISCONNECTED: +#if defined TIZEN_EXT + connman_network_set_maxspeed(network, 0); + + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + DBG("Remove signalpoll timer!!"); + } +#endif /* * If we're in one of the idle modes, we have * not started association yet and thus setting @@ -3112,8 +4026,27 @@ static void interface_state(GSupplicantInterface *interface) if (is_idle(wifi)) break; +#if defined TIZEN_EXT + if (handle_assoc_status_code(interface, wifi)) { + GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network); + guint bssid_length = 0; + + if (bssid_list) + bssid_length = g_slist_length(bssid_list); + + if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) { + network_connect(network); + break; + } + + wifi->load_shaping_retries = 0; + } + + g_hash_table_remove_all(failed_bssids); +#else if (handle_assoc_status_code(interface, wifi)) break; +#endif /* If previous state was 4way-handshake, then * it's either: psk was incorrect and thus we retry @@ -3225,6 +4158,21 @@ static void interface_removed(GSupplicantInterface *interface) wifi = g_supplicant_interface_get_data(interface); +#if defined TIZEN_EXT_WIFI_MESH + if (wifi && wifi->mesh_interface) { + DBG("Notify mesh interface remove"); + connman_mesh_notify_interface_remove(true); + struct wifi_mesh_info *mesh_info = wifi->mesh_info; + g_free(mesh_info->parent_ifname); + g_free(mesh_info->ifname); + g_free(mesh_info->identifier); + g_free(mesh_info); + wifi->mesh_interface = false; + wifi->mesh_info = NULL; + return; + } +#endif + if (wifi) wifi->interface = NULL; @@ -3239,6 +4187,9 @@ static void interface_removed(GSupplicantInterface *interface) connman_device_set_powered(wifi->device, false); check_p2p_technology(); +#if defined TIZEN_EXT_WIFI_MESH + check_mesh_technology(); +#endif } static void set_device_type(const char *type, char dev_type[17]) @@ -3378,6 +4329,97 @@ static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network) return strength; } +#if defined TIZEN_EXT_WIFI_MESH +static void mesh_peer_added(GSupplicantNetwork *supplicant_network) +{ + GSupplicantInterface *interface; + struct wifi_data *wifi; + const char *name, *security; + struct connman_mesh *connman_mesh; + struct wifi_mesh_info *mesh_info; + const unsigned char *bssid; + const char *identifier; + char *address; + uint16_t frequency; + int ret; + + interface = g_supplicant_network_get_interface(supplicant_network); + wifi = g_supplicant_interface_get_data(interface); + if (!wifi || !wifi->mesh_interface) { + DBG("Virtual Mesh interface not created"); + return; + } + + bssid = g_supplicant_network_get_bssid(supplicant_network); + address = g_malloc0(19); + snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1], + bssid[2], bssid[3], bssid[4], bssid[5]); + + identifier = g_supplicant_network_get_identifier(supplicant_network); + name = g_supplicant_network_get_name(supplicant_network); + security = g_supplicant_network_get_security(supplicant_network); + frequency = g_supplicant_network_get_frequency(supplicant_network); + + mesh_info = wifi->mesh_info; + connman_mesh = connman_mesh_get(mesh_info->identifier, identifier); + if (connman_mesh) + goto done; + + DBG("Mesh Peer name %s identifier %s security %s added", name, identifier, + security); + connman_mesh = connman_mesh_create(mesh_info->identifier, identifier); + connman_mesh_set_name(connman_mesh, name); + connman_mesh_set_security(connman_mesh, security); + connman_mesh_set_frequency(connman_mesh, frequency); + connman_mesh_set_address(connman_mesh, address); + connman_mesh_set_index(connman_mesh, mesh_info->index); + connman_mesh_set_strength(connman_mesh, + calculate_strength(supplicant_network)); + connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED); + + ret = connman_mesh_register(connman_mesh); + if (ret == -EALREADY) + DBG("Mesh Peer is already registered"); + +done: + g_free(address); +} + +static void mesh_peer_removed(GSupplicantNetwork *supplicant_network) +{ + GSupplicantInterface *interface; + struct wifi_data *wifi; + struct connman_mesh *connman_mesh; + struct wifi_mesh_info *mesh_info; + const char *identifier; + + interface = g_supplicant_network_get_interface(supplicant_network); + wifi = g_supplicant_interface_get_data(interface); + if (!wifi || !wifi->mesh_interface) { + DBG("Virtual Mesh interface not created"); + return; + } + + identifier = g_supplicant_network_get_identifier(supplicant_network); + if (!identifier) { + DBG("Failed to get Mesh Peer identifier"); + return; + } + + mesh_info = wifi->mesh_info; + connman_mesh = connman_mesh_get(mesh_info->identifier, identifier); + if (connman_mesh) { + /* Do not unregister connected mesh peer */ + if (connman_mesh_peer_is_connected_state(connman_mesh)) { + DBG("Mesh Peer %s is connected", identifier); + return; + } + DBG("Mesh Peer identifier %s removed", identifier); + connman_mesh_unregister(connman_mesh); + } +} +#endif + static void network_added(GSupplicantNetwork *supplicant_network) { struct connman_network *network; @@ -3394,6 +4436,7 @@ static void network_added(GSupplicantNetwork *supplicant_network) #if defined TIZEN_EXT GSList *vsie_list = NULL; const unsigned char *country_code; + ieee80211_modes_e phy_mode; #endif mode = g_supplicant_network_get_mode(supplicant_network); @@ -3404,6 +4447,13 @@ static void network_added(GSupplicantNetwork *supplicant_network) if (!g_strcmp0(mode, "adhoc")) return; +#if defined TIZEN_EXT_WIFI_MESH + if (!g_strcmp0(mode, "mesh")) { + mesh_peer_added(supplicant_network); + return; + } +#endif + interface = g_supplicant_network_get_interface(supplicant_network); wifi = g_supplicant_interface_get_data(interface); name = g_supplicant_network_get_name(supplicant_network); @@ -3451,6 +4501,8 @@ static void network_added(GSupplicantNetwork *supplicant_network) DBG("vsie_list is NULL"); country_code = g_supplicant_network_get_countrycode(supplicant_network); connman_network_set_countrycode(network, country_code); + phy_mode = g_supplicant_network_get_phy_mode(supplicant_network); + connman_network_set_phy_mode(network, phy_mode); #endif connman_network_set_string(network, "WiFi.Security", security); connman_network_set_strength(network, @@ -3530,6 +4582,15 @@ static void network_removed(GSupplicantNetwork *network) const char *name, *identifier; struct connman_network *connman_network; +#if defined TIZEN_EXT_WIFI_MESH + const char *mode; + mode = g_supplicant_network_get_mode(network); + if (!g_strcmp0(mode, "mesh")) { + mesh_peer_removed(network); + return; + } +#endif + interface = g_supplicant_network_get_interface(network); wifi = g_supplicant_interface_get_data(interface); identifier = g_supplicant_network_get_identifier(network); @@ -3575,6 +4636,7 @@ static void network_changed(GSupplicantNetwork *network, const char *property) uint16_t frequency; bool wps; const unsigned char *country_code; + ieee80211_modes_e phy_mode; GSList *bssid_list; #endif @@ -3603,6 +4665,7 @@ static void network_changed(GSupplicantNetwork *network, const char *property) maxrate = g_supplicant_network_get_maxrate(network); frequency = g_supplicant_network_get_frequency(network); wps = g_supplicant_network_get_wps(network); + phy_mode = g_supplicant_network_get_phy_mode(network); connman_network_set_bssid(connman_network, bssid); connman_network_set_maxrate(connman_network, maxrate); @@ -3612,6 +4675,11 @@ static void network_changed(GSupplicantNetwork *network, const char *property) connman_network_set_countrycode(connman_network, country_code); bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network); connman_network_set_bssid_list(connman_network, bssid_list); + connman_network_set_phy_mode(connman_network, phy_mode); + + if (g_str_equal(property, "CheckMultiBssidConnect") && + connman_network_get_associating(connman_network)) + network_connect(connman_network); #endif } @@ -4013,6 +5081,13 @@ static const GSupplicantCallbacks callbacks = { .debug = debug, .disconnect_reasoncode = disconnect_reasoncode, .assoc_status_code = assoc_status_code, +#if defined TIZEN_EXT_WIFI_MESH + .mesh_support = mesh_support, + .mesh_group_started = mesh_group_started, + .mesh_group_removed = mesh_group_removed, + .mesh_peer_connected = mesh_peer_connected, + .mesh_peer_disconnected = mesh_peer_disconnected, +#endif }; @@ -4038,7 +5113,11 @@ static GSupplicantSSID *ssid_ap_init(const char *ssid, return NULL; ap->mode = G_SUPPLICANT_MODE_MASTER; +#if defined TIZEN_EXT + ap->ssid = (void *) ssid; +#else ap->ssid = ssid; +#endif ap->ssid_len = strlen(ssid); ap->scan_ssid = 0; ap->freq = 2412; @@ -4345,6 +5424,9 @@ static int wifi_init(void) return err; } +#if defined TIZEN_EXT + failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); +#endif return 0; } @@ -4357,6 +5439,10 @@ static void wifi_exit(void) g_supplicant_unregister(&callbacks); connman_network_driver_unregister(&network_driver); + +#if defined TIZEN_EXT + g_hash_table_unref(failed_bssids); +#endif } CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,