From 6b2381a2adabea7d8309ff158ef675ff88184305 Mon Sep 17 00:00:00 2001 From: Nishant Chaprana Date: Thu, 4 Jul 2019 17:41:09 +0530 Subject: Imported Upstream version 1.37 Change-Id: Ib5957e7ee3a9315ee86a331189bc3e9e71751ee8 Signed-off-by: Nishant Chaprana --- plugins/ethernet.c | 4 +- plugins/gadget.c | 4 + plugins/iospm.c | 2 +- plugins/iwd.c | 97 ++++++-------- plugins/nmcompat.c | 2 +- plugins/ofono.c | 5 +- plugins/pacrunner.c | 2 +- plugins/session_policy_local.c | 6 +- plugins/tist.c | 1 - plugins/vpn.c | 231 +++++++++++++++++++++++++++------ plugins/wifi.c | 287 ++++++++++++++++++++++++++++++++--------- 11 files changed, 470 insertions(+), 171 deletions(-) (limited to 'plugins') diff --git a/plugins/ethernet.c b/plugins/ethernet.c index 9a4d7413..b0395c83 100644 --- a/plugins/ethernet.c +++ b/plugins/ethernet.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -187,11 +188,12 @@ static void add_network(struct connman_device *device, if (connman_device_add_network(device, network) < 0) { connman_network_unref(network); + g_free(ifname); return; } if (!eth_tethering) { - char group[16] = "cable"; + char group[25] = "cable"; int vid, dsaport; vid = get_vlan_vid(ifname); diff --git a/plugins/gadget.c b/plugins/gadget.c index 94f66487..1b44bbb5 100644 --- a/plugins/gadget.c +++ b/plugins/gadget.c @@ -270,6 +270,8 @@ static void gadget_tech_enable_tethering(struct connman_technology *technology, connman_inet_ifup(index); connman_inet_add_to_bridge(index, bridge); + + gadget_tethering = true; } } @@ -286,6 +288,8 @@ static void gadget_tech_disable_tethering(struct connman_technology *technology, connman_inet_ifdown(index); connman_technology_tethering_notify(technology, false); + + gadget_tethering = false; } } diff --git a/plugins/iospm.c b/plugins/iospm.c index fcb4cea1..cded9e00 100644 --- a/plugins/iospm.c +++ b/plugins/iospm.c @@ -86,7 +86,7 @@ static void iospm_offline_mode(bool enabled) send_indication(IOSPM_FLIGHT_MODE, enabled); } -static struct connman_notifier iospm_notifier = { +static const struct connman_notifier iospm_notifier = { .name = "iospm", .priority = CONNMAN_NOTIFIER_PRIORITY_DEFAULT, .service_enabled= iospm_service_enabled, diff --git a/plugins/iwd.c b/plugins/iwd.c index b5191654..ddc9201d 100644 --- a/plugins/iwd.c +++ b/plugins/iwd.c @@ -55,14 +55,6 @@ static bool agent_registered; #define IWD_AGENT_ERROR_INTERFACE "net.connman.iwd.Agent.Error" #define AGENT_PATH "/net/connman/iwd_agent" -enum iwd_device_state { - IWD_DEVICE_STATE_UNKNOWN, - IWD_DEVICE_STATE_CONNECTED, - IWD_DEVICE_STATE_DISCONNECTED, - IWD_DEVICE_STATE_CONNECTING, - IWD_DEVICE_STATE_DISCONNECTING, -}; - struct iwd_adapter { GDBusProxy *proxy; char *path; @@ -77,7 +69,6 @@ struct iwd_device { char *adapter; char *name; char *address; - enum iwd_device_state state; bool powered; bool scanning; @@ -96,38 +87,6 @@ struct iwd_network { struct connman_network *network; }; -static enum iwd_device_state string2state(const char *str) -{ - if (!strcmp(str, "connected")) - return IWD_DEVICE_STATE_CONNECTED; - else if (!strcmp(str, "disconnected")) - return IWD_DEVICE_STATE_DISCONNECTED; - else if (!strcmp(str, "connecting")) - return IWD_DEVICE_STATE_CONNECTING; - else if (!strcmp(str, "disconnecting")) - return IWD_DEVICE_STATE_DISCONNECTING; - - return IWD_DEVICE_STATE_UNKNOWN; -} - -static const char *state2string(enum iwd_device_state state) -{ - switch (state) { - case IWD_DEVICE_STATE_CONNECTED: - return "connected"; - case IWD_DEVICE_STATE_DISCONNECTED: - return "disconnected"; - case IWD_DEVICE_STATE_CONNECTING: - return "connecting"; - case IWD_DEVICE_STATE_DISCONNECTING: - return "disconnecting"; - default: - break; - } - - return "unknown"; -} - static const char *proxy_get_string(GDBusProxy *proxy, const char *property) { DBusMessageIter iter; @@ -484,17 +443,53 @@ static void update_signal_strength(struct iwd_device *iwdd) DBG("GetOrderedNetworks() failed"); } +static const char *security_remap(const char *security) +{ + if (!g_strcmp0(security, "open")) + return "none"; + else if (!g_strcmp0(security, "psk")) + return "psk"; + else if (!g_strcmp0(security, "8021x")) + return "ieee8021x"; + + return "unknown"; +} + +static char *create_identifier(const char *path, const char *security) +{ + char *start, *end, *identifier; + char *_path = g_strdup(path); + + /* + * _path is something like + * /0/4/5363686970686f6c5f427573696e6573735f454150_8021x + */ + start = strrchr(_path, '/'); + start++; + end = strchr(start, '_'); + *end = '\0'; + + /* + * Create an ident which is identical to the corresponding + * wpa_supplicant identifier. + */ + identifier = g_strdup_printf("%s_managed_%s", start, + security_remap(security)); + g_free(_path); + + return identifier; +} + static void add_network(const char *path, struct iwd_network *iwdn) { struct iwd_device *iwdd; - const char *identifier; + char *identifier; iwdd = g_hash_table_lookup(devices, iwdn->device); if (!iwdd) return; - identifier = strrchr(path, '/'); - identifier++; /* strip leading slash as well */ + identifier = create_identifier(path, iwdn->type); iwdn->network = connman_network_create(identifier, CONNMAN_NETWORK_TYPE_WIFI); connman_network_set_data(iwdn->network, iwdn); @@ -504,6 +499,7 @@ static void add_network(const char *path, struct iwd_network *iwdn) strlen(iwdn->name)); connman_network_set_string(iwdn->network, "WiFi.Security", iwdn->type); + connman_network_set_string(iwdn->network, "WiFi.Mode", "managed"); if (connman_device_add_network(iwdd->device, iwdn->network) < 0) { connman_network_unref(iwdn->network); @@ -514,6 +510,8 @@ static void add_network(const char *path, struct iwd_network *iwdn) connman_network_set_available(iwdn->network, true); connman_network_set_group(iwdn->network, identifier); + + g_free(identifier); } static void remove_network(struct iwd_network *iwdn) @@ -625,13 +623,6 @@ static void device_property_change(GDBusProxy *proxy, const char *name, iwdd->name = g_strdup(name); DBG("%p name %s", path, iwdd->name); - } else if (!strcmp(name, "State")) { - const char *state; - - dbus_message_iter_get_basic(iter, &state); - iwdd->state = string2state(state); - - DBG("%s state %s", path, state2string(iwdd->state)); } else if (!strcmp(name, "Powered")) { dbus_bool_t powered; @@ -790,13 +781,11 @@ static void create_device(GDBusProxy *proxy) iwdd->adapter = g_strdup(proxy_get_string(proxy, "Adapter")); iwdd->name = g_strdup(proxy_get_string(proxy, "Name")); iwdd->address = g_strdup(proxy_get_string(proxy, "Address")); - iwdd->state = string2state(proxy_get_string(proxy, "State")); iwdd->powered = proxy_get_bool(proxy, "Powered"); iwdd->scanning = proxy_get_bool(proxy, "Scanning"); - DBG("adapter %s name %s address %s state %s powered %d scanning %d", + DBG("adapter %s name %s address %s powered %d scanning %d", iwdd->adapter, iwdd->name, iwdd->address, - state2string(iwdd->state), iwdd->powered, iwdd->scanning); g_dbus_proxy_set_property_watch(iwdd->proxy, diff --git a/plugins/nmcompat.c b/plugins/nmcompat.c index 883ce9bd..274baab4 100644 --- a/plugins/nmcompat.c +++ b/plugins/nmcompat.c @@ -173,7 +173,7 @@ static void offline_mode(bool enabled) current_service = NULL; } -static struct connman_notifier notifier = { +static const struct connman_notifier notifier = { .name = "nmcompat", .priority = CONNMAN_NOTIFIER_PRIORITY_DEFAULT, .default_changed = default_changed, diff --git a/plugins/ofono.c b/plugins/ofono.c index 78f8f196..82413b6e 100644 --- a/plugins/ofono.c +++ b/plugins/ofono.c @@ -1301,10 +1301,13 @@ static void remove_all_contexts(struct modem_data *modem) if (modem->context_list == NULL) return; - for (list = modem->context_list; list; list = list->next) { + list = modem->context_list; + while (list) { struct network_context *context = list->data; remove_cm_context(modem, context); + + list = modem->context_list; } g_slist_free(modem->context_list); modem->context_list = NULL; diff --git a/plugins/pacrunner.c b/plugins/pacrunner.c index d2464a5e..9c652f3b 100644 --- a/plugins/pacrunner.c +++ b/plugins/pacrunner.c @@ -277,7 +277,7 @@ static void proxy_changed(struct connman_service *service) create_proxy_configuration(); } -static struct connman_notifier pacrunner_notifier = { +static const struct connman_notifier pacrunner_notifier = { .name = "pacrunner", .default_changed = default_service_changed, .proxy_changed = proxy_changed, diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c index f003c0e1..9beb0980 100644 --- a/plugins/session_policy_local.c +++ b/plugins/session_policy_local.c @@ -271,10 +271,8 @@ static void get_uid_reply(unsigned int uid, void *user_data, int err) DBG("session %p uid %d", policy->session, uid); - if (err < 0) { - cleanup_config(policy); + if (err < 0) goto err; - } pwd = getpwuid((uid_t)uid); if (!pwd) { @@ -333,7 +331,7 @@ static void get_uid_reply(unsigned int uid, void *user_data, int err) return; err: - failed_create(NULL, cb, cbd->user_data, err); + failed_create(policy, cb, cbd->user_data, err); g_free(cbd); g_free(groups); } diff --git a/plugins/tist.c b/plugins/tist.c index ad5ef79e..cc2800a1 100644 --- a/plugins/tist.c +++ b/plugins/tist.c @@ -23,7 +23,6 @@ #include #endif -#define _GNU_SOURCE #include #include #include diff --git a/plugins/vpn.c b/plugins/vpn.c index c2a332ba..11bab154 100644 --- a/plugins/vpn.c +++ b/plugins/vpn.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -71,8 +72,10 @@ struct connection_data { struct connman_provider *provider; int index; DBusPendingCall *call; + DBusPendingCall *disconnect_call; bool connect_pending; struct config_create_data *cb_data; + char *service_ident; char *state; char *type; @@ -249,6 +252,12 @@ static void free_config_cb_data(struct config_create_data *cb_data) g_free(cb_data); } +static bool provider_is_connected(struct connection_data *data) +{ + return data && (g_str_equal(data->state, "ready") || + g_str_equal(data->state, "configuration")); +} + static void set_provider_state(struct connection_data *data) { enum connman_provider_state state = CONNMAN_PROVIDER_STATE_UNKNOWN; @@ -256,6 +265,11 @@ static void set_provider_state(struct connection_data *data) DBG("provider %p new state %s", data->provider, data->state); + if (!provider_is_connected(data)) { + g_free(data->service_ident); + data->service_ident = NULL; + } + if (g_str_equal(data->state, "ready")) { state = CONNMAN_PROVIDER_STATE_READY; goto set; @@ -484,19 +498,19 @@ static void connect_reply(DBusPendingCall *call, void *user_data) if (dbus_set_error_from_message(&error, reply)) { int err = errorstr2val(error.name); + if (err != -EINPROGRESS) { connman_error("Connect reply: %s (%s)", error.message, error.name); - dbus_error_free(&error); - DBG("data %p cb_data %p", data, cb_data); + if (cb_data) { cb_data->callback(cb_data->message, err, NULL); free_config_cb_data(cb_data); data->cb_data = NULL; } - goto done; } + dbus_error_free(&error); } @@ -506,7 +520,6 @@ static void connect_reply(DBusPendingCall *call, void *user_data) * state. */ -done: dbus_message_unref(reply); dbus_pending_call_unref(call); @@ -518,24 +531,31 @@ static int connect_provider(struct connection_data *data, void *user_data, DBusPendingCall *call; DBusMessage *message; struct config_create_data *cb_data = user_data; + struct connman_service *transport = connman_service_get_default(); DBG("data %p user %p path %s sender %s", data, cb_data, data->path, dbus_sender); - data->connect_pending = false; + if (!transport) { + DBG("no default service, refusing to connect"); + return -EINVAL; + } -#define VPN_CONNECT2 "Connect2" + data->connect_pending = false; /* We need to pass original dbus sender to connman-vpnd, - * use a Connect2 method for that. + * use a Connect2 method for that if the original dbus sender is set. + * Connect method requires no parameter, Connect2 requires dbus sender + * name to be set. */ message = dbus_message_new_method_call(VPN_SERVICE, data->path, VPN_CONNECTION_INTERFACE, - VPN_CONNECT2); + dbus_sender && *dbus_sender ? + VPN_CONNECT2 : VPN_CONNECT); if (!message) return -ENOMEM; - if (dbus_sender) + if (dbus_sender && *dbus_sender) dbus_message_append_args(message, DBUS_TYPE_STRING, &dbus_sender, NULL); else @@ -544,7 +564,8 @@ static int connect_provider(struct connection_data *data, void *user_data, if (!dbus_connection_send_with_reply(connection, message, &call, DBUS_TIMEOUT)) { connman_error("Unable to call %s.%s()", - VPN_CONNECTION_INTERFACE, VPN_CONNECT2); + VPN_CONNECTION_INTERFACE, dbus_sender && *dbus_sender ? + VPN_CONNECT2 : VPN_CONNECT); dbus_message_unref(message); return -EINVAL; } @@ -559,6 +580,15 @@ static int connect_provider(struct connection_data *data, void *user_data, cb_data->path = g_strdup(data->path); } + /* + * This is the service which (most likely) will be used + * as a transport for VPN connection. + */ + g_free(data->service_ident); + data->service_ident = + g_strdup(connman_service_get_identifier(transport)); + DBG("transport %s", data->service_ident); + dbus_pending_call_set_notify(call, connect_reply, data, NULL); dbus_message_unref(message); @@ -891,12 +921,10 @@ static int provider_connect(struct connman_provider *provider, static void disconnect_reply(DBusPendingCall *call, void *user_data) { + struct connection_data *data = user_data; DBusMessage *reply; DBusError error; - if (!dbus_pending_call_get_completed(call)) - return; - DBG("user %p", user_data); reply = dbus_pending_call_steal_reply(call); @@ -911,50 +939,47 @@ static void disconnect_reply(DBusPendingCall *call, void *user_data) done: dbus_message_unref(reply); - dbus_pending_call_unref(call); + data->disconnect_call = NULL; } static int disconnect_provider(struct connection_data *data) { - DBusPendingCall *call; + bool sent; DBusMessage *message; DBG("data %p path %s", data, data->path); + if (data->disconnect_call) { + DBG("already disconnecting"); + return -EINVAL; + } + message = dbus_message_new_method_call(VPN_SERVICE, data->path, VPN_CONNECTION_INTERFACE, VPN_DISCONNECT); if (!message) return -ENOMEM; - if (!dbus_connection_send_with_reply(connection, message, - &call, DBUS_TIMEOUT)) { + sent = dbus_connection_send_with_reply(connection, message, + &data->disconnect_call, DBUS_TIMEOUT); + dbus_message_unref(message); + + if (!sent || !data->disconnect_call) { connman_error("Unable to call %s.%s()", VPN_CONNECTION_INTERFACE, VPN_DISCONNECT); - dbus_message_unref(message); return -EINVAL; } - if (!call) { - dbus_message_unref(message); - return -EINVAL; - } + dbus_pending_call_set_notify(data->disconnect_call, disconnect_reply, + data, NULL); - dbus_pending_call_set_notify(call, disconnect_reply, NULL, NULL); - - dbus_message_unref(message); + g_free(data->service_ident); + data->service_ident = NULL; connman_provider_set_state(data->provider, CONNMAN_PROVIDER_STATE_DISCONNECT); - /* - * We return 0 here instead of -EINPROGRESS because - * __connman_service_disconnect() needs to return something - * to gdbus so that gdbus will not call Disconnect() more - * than once. This way we do not need to pass the dbus reply - * message around the code. - */ - return 0; + return -EINPROGRESS; } static int provider_disconnect(struct connman_provider *provider) @@ -967,8 +992,7 @@ static int provider_disconnect(struct connman_provider *provider) if (!data) return -EINVAL; - if (g_str_equal(data->state, "ready") || - g_str_equal(data->state, "configuration")) + if (provider_is_connected(data)) return disconnect_provider(data); return 0; @@ -1476,17 +1500,11 @@ static void destroy_provider(struct connection_data *data) { DBG("data %p", data); - if (g_str_equal(data->state, "ready") || - g_str_equal(data->state, "configuration")) + if (provider_is_connected(data)) connman_provider_disconnect(data->provider); - if (data->call) - dbus_pending_call_cancel(data->call); - connman_provider_set_data(data->provider, NULL); - connman_provider_remove(data->provider); - data->provider = NULL; } @@ -1499,13 +1517,24 @@ static void connection_destroy(gpointer hash_data) if (data->provider) destroy_provider(data); + if (data->call) { + dbus_pending_call_cancel(data->call); + dbus_pending_call_unref(data->call); + } + + if (data->disconnect_call) { + dbus_pending_call_cancel(data->disconnect_call); + dbus_pending_call_unref(data->disconnect_call); + } + + g_free(data->service_ident); g_free(data->path); g_free(data->ident); g_free(data->state); g_free(data->type); g_free(data->name); g_free(data->host); - g_free(data->host_ip); + g_strfreev(data->host_ip); g_free(data->domain); g_hash_table_destroy(data->server_routes); g_hash_table_destroy(data->user_routes); @@ -1813,6 +1842,120 @@ static gboolean property_changed(DBusConnection *conn, return TRUE; } +static int vpn_find_online_transport_cb(struct connman_service *service, + void *user_data) +{ + if (connman_service_get_type(service) != CONNMAN_SERVICE_TYPE_VPN) { + switch (connman_service_get_state(service)) { + case CONNMAN_SERVICE_STATE_ONLINE: + *((struct connman_service**)user_data) = service; + return 1; + default: + break; + } + } + + return 0; +} + +static struct connman_service *vpn_find_online_transport() +{ + struct connman_service *service = NULL; + + connman_service_iterate_services(vpn_find_online_transport_cb, + &service); + return service; +} + +static bool vpn_is_valid_transport(struct connman_service *transport) +{ + if (transport) { + struct connman_service *online; + + switch (connman_service_get_state(transport)) { + case CONNMAN_SERVICE_STATE_READY: + online = vpn_find_online_transport(); + + /* Stay connected if there are no online services */ + if (!online) + return true; + + DBG("%s is ready, %s is online, disconnecting", + connman_service_get_identifier(transport), + connman_service_get_identifier(online)); + break; + + case CONNMAN_SERVICE_STATE_ONLINE: + online = vpn_find_online_transport(); + + /* Check if our transport is still the default */ + if (online == transport) + return true; + + DBG("%s is replaced by %s as default, disconnecting", + connman_service_get_identifier(transport), + connman_service_get_identifier(online)); + break; + + default: + break; + } + } else { + DBG("transport gone"); + } + + return false; +} + +static void vpn_disconnect_check_provider(struct connection_data *data) +{ + if (data->service_ident && provider_is_connected(data)) { + struct connman_service *service = + connman_service_lookup_from_identifier + (data->service_ident); + + if (!vpn_is_valid_transport(service)) { + disconnect_provider(data); + } + } +} + +static void vpn_disconnect_check() +{ + GHashTableIter iter; + gpointer value; + + DBG(""); + g_hash_table_iter_init(&iter, vpn_connections); + while (g_hash_table_iter_next(&iter, NULL, &value)) + vpn_disconnect_check_provider(value); +} + +static void vpn_service_add(struct connman_service *service, const char *name) +{ + vpn_disconnect_check(); +} + +static void vpn_service_list_changed(struct connman_service *service) +{ + vpn_disconnect_check(); +} + +static void vpn_service_state_changed(struct connman_service *service, + enum connman_service_state state) +{ + vpn_disconnect_check(); +} + +static const struct connman_notifier vpn_notifier = { + .name = "vpn", + .priority = CONNMAN_NOTIFIER_PRIORITY_DEFAULT, + .default_changed = vpn_service_list_changed, + .service_add = vpn_service_add, + .service_remove = vpn_service_list_changed, + .service_state_changed = vpn_service_state_changed +}; + static int vpn_init(void) { int err; @@ -1853,6 +1996,7 @@ static int vpn_init(void) vpnd_created(connection, &provider_driver); } + connman_notifier_register(&vpn_notifier); return err; remove: @@ -1873,6 +2017,7 @@ static void vpn_exit(void) g_dbus_remove_watch(connection, removed_watch); g_dbus_remove_watch(connection, property_watch); + connman_notifier_unregister(&vpn_notifier); connman_provider_driver_unregister(&provider_driver); if (vpn_connections) diff --git a/plugins/wifi.c b/plugins/wifi.c index 34c16dfd..f8c22be3 100644 --- a/plugins/wifi.c +++ b/plugins/wifi.c @@ -30,9 +30,8 @@ #include #include #include -#include -#include #include +#include #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 @@ -56,6 +55,7 @@ #include #include #include +#include #include @@ -64,7 +64,8 @@ #define FAVORITE_MAXIMUM_RETRIES 2 #define BGSCAN_DEFAULT "simple:30:-45:300" -#define AUTOSCAN_DEFAULT "exponential:3:300" +#define AUTOSCAN_EXPONENTIAL "exponential:3:300" +#define AUTOSCAN_SINGLE "single:3" #define P2P_FIND_TIMEOUT 30 #define P2P_CONNECTION_TIMEOUT 100 @@ -83,6 +84,12 @@ enum wifi_ap_capability{ WIFI_AP_NOT_SUPPORTED = 2, }; +enum wifi_scanning_type { + WIFI_SCANNING_UNKNOWN = 0, + WIFI_SCANNING_PASSIVE = 1, + WIFI_SCANNING_ACTIVE = 2, +}; + struct hidden_params { char ssid[32]; unsigned int ssid_len; @@ -143,7 +150,7 @@ struct wifi_data { * autoscan "emulation". */ struct autoscan_params *autoscan; - + enum wifi_scanning_type scanning_type; GSupplicantScanParams *scan_params; unsigned int p2p_find_timeout; unsigned int p2p_connection_timeout; @@ -160,7 +167,7 @@ static GList *iface_list = NULL; static GList *pending_wifi_device = NULL; static GList *p2p_iface_list = NULL; -bool wfd_service_registered = false; +static bool wfd_service_registered = false; static void start_autoscan(struct connman_device *device); static int tech_set_tethering(struct connman_technology *technology, @@ -596,10 +603,8 @@ static int peer_register_service(const unsigned char *specification, params = fill_in_peer_service_params(specification, specification_length, query, query_length, version); - if (!params) { - ret = -ENOMEM; + if (!params) continue; - } if (!found) { ret_f = g_supplicant_interface_p2p_add_service(iface, @@ -684,10 +689,8 @@ static int peer_unregister_service(const unsigned char *specification, params = fill_in_peer_service_params(specification, specification_length, query, query_length, version); - if (!params) { - ret = -ENOMEM; + if (!params) continue; - } ret = g_supplicant_interface_p2p_del_service(iface, params); if (ret != 0 && ret != -EINPROGRESS) @@ -831,13 +834,13 @@ static void reset_autoscan(struct connman_device *device) autoscan = wifi->autoscan; - if (autoscan->timeout == 0 && autoscan->interval == 0) + autoscan->interval = 0; + + if (autoscan->timeout == 0) return; g_source_remove(autoscan->timeout); - autoscan->timeout = 0; - autoscan->interval = 0; connman_device_unref(device); } @@ -893,7 +896,7 @@ static void wifi_remove(struct connman_device *device) remove_pending_wifi_device(wifi); - if (wifi->p2p_find_timeout) { + if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) { g_source_remove(wifi->p2p_find_timeout); connman_device_unref(wifi->device); } @@ -1209,7 +1212,7 @@ static int throw_wifi_scan(struct connman_device *device, if (wifi->tethering) return -EBUSY; - if (connman_device_get_scanning(device)) + if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) return -EALREADY; connman_device_ref(device); @@ -1283,7 +1286,7 @@ static void scan_callback(int result, GSupplicantInterface *interface, return scan_callback(ret, interface, user_data); } - scanning = connman_device_get_scanning(device); + scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI); if (scanning) { connman_device_set_scanning(device, @@ -1363,6 +1366,21 @@ static gboolean autoscan_timeout(gpointer data) throw_wifi_scan(wifi->device, scan_callback_hidden); + /* + * In case BackgroundScanning is disabled, interval will reach the + * limit exactly after the very first passive scanning. It allows + * to ensure at most one passive scan is performed in such cases. + */ + if (!connman_setting_get_bool("BackgroundScanning") && + interval == autoscan->limit) { + g_source_remove(autoscan->timeout); + autoscan->timeout = 0; + + connman_device_unref(device); + + return FALSE; + } + set_interval: DBG("interval %d", interval); @@ -1409,19 +1427,25 @@ static struct autoscan_params *parse_autoscan_params(const char *params) int limit; int base; - DBG("Emulating autoscan"); + DBG(""); list_params = g_strsplit(params, ":", 0); if (list_params == 0) return NULL; - if (g_strv_length(list_params) < 3) { + if (!g_strcmp0(list_params[0], "exponential") && + g_strv_length(list_params) == 3) { + base = atoi(list_params[1]); + limit = atoi(list_params[2]); + } else if (!g_strcmp0(list_params[0], "single") && + g_strv_length(list_params) == 2) + base = limit = atoi(list_params[1]); + else { g_strfreev(list_params); return NULL; } - base = atoi(list_params[1]); - limit = atoi(list_params[2]); + DBG("Setup %s autoscanning", list_params[0]); g_strfreev(list_params); @@ -1440,10 +1464,37 @@ static struct autoscan_params *parse_autoscan_params(const char *params) static void setup_autoscan(struct wifi_data *wifi) { - if (!wifi->autoscan) - wifi->autoscan = parse_autoscan_params(AUTOSCAN_DEFAULT); + /* + * If BackgroundScanning is enabled, setup exponential + * autoscanning if it has not been previously done. + */ + if (connman_setting_get_bool("BackgroundScanning")) { + wifi->autoscan = parse_autoscan_params(AUTOSCAN_EXPONENTIAL); + return; + } - start_autoscan(wifi->device); + /* + * On the contrary, if BackgroundScanning is disabled, update autoscan + * parameters based on the type of scanning that is being performed. + */ + if (wifi->autoscan) { + g_free(wifi->autoscan); + wifi->autoscan = NULL; + } + + switch (wifi->scanning_type) { + case WIFI_SCANNING_PASSIVE: + /* Do not setup autoscan. */ + break; + case WIFI_SCANNING_ACTIVE: + /* Setup one single passive scan after active. */ + wifi->autoscan = parse_autoscan_params(AUTOSCAN_SINGLE); + break; + case WIFI_SCANNING_UNKNOWN: + /* Setup autoscan in this case but we should never fall here. */ + wifi->autoscan = parse_autoscan_params(AUTOSCAN_SINGLE); + break; + } } static void finalize_interface_creation(struct wifi_data *wifi) @@ -1457,13 +1508,13 @@ static void finalize_interface_creation(struct wifi_data *wifi) connman_device_set_powered(wifi->device, true); - if (!connman_setting_get_bool("BackgroundScanning")) - return; - if (wifi->p2p_device) return; - setup_autoscan(wifi); + if (!wifi->autoscan) + setup_autoscan(wifi); + + start_autoscan(wifi->device); } static void interface_create_callback(int result, @@ -1535,7 +1586,7 @@ static int wifi_disable(struct connman_device *device) stop_autoscan(device); - if (wifi->p2p_find_timeout) { + if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) { g_source_remove(wifi->p2p_find_timeout); wifi->p2p_find_timeout = 0; connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false); @@ -1543,7 +1594,7 @@ static int wifi_disable(struct connman_device *device) } /* In case of a user scan, device is still referenced */ - if (connman_device_get_scanning(device)) { + if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) { connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_WIFI, false); connman_device_unref(wifi->device); @@ -1691,10 +1742,29 @@ static int get_latest_connections(int max_ssids, return num_ssids; } +static void wifi_update_scanner_type(struct wifi_data *wifi, + enum wifi_scanning_type new_type) +{ + DBG(""); + + if (!wifi || wifi->scanning_type == new_type) + return; + + wifi->scanning_type = new_type; + + setup_autoscan(wifi); +} + static int wifi_scan_simple(struct connman_device *device) { + struct wifi_data *wifi = connman_device_get_data(device); + reset_autoscan(device); + /* Distinguish between devices performing passive and active scanning */ + if (wifi) + wifi_update_scanner_type(wifi, WIFI_SCANNING_PASSIVE); + return throw_wifi_scan(device, scan_callback_hidden); } @@ -1714,7 +1784,7 @@ static gboolean p2p_find_stop(gpointer data) connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false); connman_device_unref(device); - reset_autoscan(device); + start_autoscan(device); return FALSE; } @@ -1783,11 +1853,8 @@ static int p2p_find(struct connman_device *device) * Note that the hidden scan is only used when connecting to this specific * hidden AP first time. It is not used when system autoconnects to hidden AP. */ -static int wifi_scan(enum connman_service_type type, - struct connman_device *device, - const char *ssid, unsigned int ssid_len, - const char *identity, const char* passphrase, - const char *security, void *user_data) +static int wifi_scan(struct connman_device *device, + struct connman_device_scan_params *params) { struct wifi_data *wifi = connman_device_get_data(device); GSupplicantScanParams *scan_params = NULL; @@ -1807,14 +1874,15 @@ static int wifi_scan(enum connman_service_type type, if (wifi->tethering) return -EBUSY; - if (type == CONNMAN_SERVICE_TYPE_P2P) + if (params->type == CONNMAN_SERVICE_TYPE_P2P) return p2p_find(device); - DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, ssid); + DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, + params->ssid); - scanning = connman_device_get_scanning(device); + scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI); - if (!ssid || ssid_len == 0 || ssid_len > 32) { + if (!params->ssid || params->ssid_len == 0 || params->ssid_len > 32) { if (scanning) return -EALREADY; @@ -1843,8 +1911,8 @@ static int wifi_scan(enum connman_service_type type, return -ENOMEM; } - memcpy(scan_ssid->ssid, ssid, ssid_len); - scan_ssid->ssid_len = ssid_len; + memcpy(scan_ssid->ssid, params->ssid, params->ssid_len); + scan_ssid->ssid_len = params->ssid_len; scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); scan_params->num_ssids = 1; @@ -1860,12 +1928,12 @@ static int wifi_scan(enum connman_service_type type, wifi->hidden = NULL; } - memcpy(hidden->ssid, ssid, ssid_len); - hidden->ssid_len = ssid_len; - hidden->identity = g_strdup(identity); - hidden->passphrase = g_strdup(passphrase); - hidden->security = g_strdup(security); - hidden->user_data = user_data; + memcpy(hidden->ssid, params->ssid, params->ssid_len); + hidden->ssid_len = params->ssid_len; + hidden->identity = g_strdup(params->identity); + hidden->passphrase = g_strdup(params->passphrase); + hidden->security = g_strdup(params->security); + hidden->user_data = params->user_data; wifi->hidden = hidden; if (scanning) { @@ -1879,7 +1947,7 @@ static int wifi_scan(enum connman_service_type type, } else if (wifi->connected) { g_supplicant_free_scan_params(scan_params); return wifi_scan_simple(device); - } else { + } else if (!params->force_full_scan) { ret = get_latest_connections(driver_max_ssids, scan_params); if (ret <= 0) { g_supplicant_free_scan_params(scan_params); @@ -1887,6 +1955,9 @@ static int wifi_scan(enum connman_service_type type, } } + /* Distinguish between devices performing passive and active scanning */ + wifi_update_scanner_type(wifi, WIFI_SCANNING_ACTIVE); + connman_device_ref(device); reset_autoscan(device); @@ -1909,6 +1980,24 @@ static int wifi_scan(enum connman_service_type type, return ret; } +static void wifi_stop_scan(enum connman_service_type type, + struct connman_device *device) +{ + struct wifi_data *wifi = connman_device_get_data(device); + + DBG("device %p wifi %p", device, wifi); + + if (!wifi) + return; + + if (type == CONNMAN_SERVICE_TYPE_P2P) { + if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) { + g_source_remove(wifi->p2p_find_timeout); + p2p_find_stop(device); + } + } +} + static void wifi_regdom_callback(int result, const char *alpha2, void *user_data) @@ -1948,6 +2037,7 @@ static struct connman_device_driver wifi_ng_driver = { .enable = wifi_enable, .disable = wifi_disable, .scan = wifi_scan, + .stop_scan = wifi_stop_scan, .set_regdom = wifi_set_regdom, }; @@ -2138,10 +2228,9 @@ static void disconnect_callback(int result, GSupplicantInterface *interface, return; } - if (wifi->network) { + if (wifi->network != wifi->pending_network) connman_network_set_connected(wifi->network, false); - wifi->network = NULL; - } + wifi->network = NULL; wifi->disconnecting = false; wifi->connected = false; @@ -2370,17 +2459,20 @@ static void interface_state(GSupplicantInterface *interface) if (!wifi) return; + device = wifi->device; + if (!device) + return; + if (state == G_SUPPLICANT_STATE_COMPLETED) { if (wifi->tethering_param) { g_free(wifi->tethering_param->ssid); g_free(wifi->tethering_param); wifi->tethering_param = NULL; } - } - device = wifi->device; - if (!device) - return; + if (wifi->tethering) + stop_autoscan(device); + } if (g_supplicant_interface_get_ready(interface) && !wifi->interface_ready) { @@ -2461,8 +2553,11 @@ static void interface_state(GSupplicantInterface *interface) default: break; } - connman_network_set_connected(network, false); - connman_network_set_associating(network, false); + + if (network != wifi->pending_network) { + connman_network_set_connected(network, false); + connman_network_set_associating(network, false); + } wifi->disconnecting = false; start_autoscan(device); @@ -2635,8 +2730,6 @@ static void ap_create_fail(GSupplicantInterface *interface) g_free(wifi->tethering_param); wifi->tethering_param = NULL; } - - return; } static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network) @@ -2714,6 +2807,8 @@ static void network_added(GSupplicantNetwork *supplicant_network) connman_network_set_strength(network, calculate_strength(supplicant_network)); connman_network_set_bool(network, "WiFi.WPS", wps); + connman_network_set_bool(network, "WiFi.WPSAdvertising", + wps_advertizing); if (wps) { /* Is AP advertizing for WPS association? @@ -2780,6 +2875,7 @@ static void network_changed(GSupplicantNetwork *network, const char *property) struct wifi_data *wifi; const char *name, *identifier; struct connman_network *connman_network; + bool update_needed; interface = g_supplicant_network_get_interface(network); wifi = g_supplicant_interface_get_data(interface); @@ -2795,11 +2891,42 @@ static void network_changed(GSupplicantNetwork *network, const char *property) if (!connman_network) return; - if (g_str_equal(property, "Signal")) { - connman_network_set_strength(connman_network, + if (g_str_equal(property, "WPSCapabilities")) { + bool wps; + bool wps_pbc; + bool wps_ready; + bool wps_advertizing; + + wps = g_supplicant_network_get_wps(network); + wps_pbc = g_supplicant_network_is_wps_pbc(network); + wps_ready = g_supplicant_network_is_wps_active(network); + wps_advertizing = + g_supplicant_network_is_wps_advertizing(network); + + connman_network_set_bool(connman_network, "WiFi.WPS", wps); + connman_network_set_bool(connman_network, + "WiFi.WPSAdvertising", wps_advertizing); + + if (wps) { + /* + * Is AP advertizing for WPS association? + * If so, we decide to use WPS by default + */ + if (wps_ready && wps_pbc && wps_advertizing) + connman_network_set_bool(connman_network, + "WiFi.UseWPS", true); + } + + update_needed = true; + } else if (g_str_equal(property, "Signal")) { + connman_network_set_strength(connman_network, calculate_strength(network)); - connman_network_update(connman_network); - } + update_needed = true; + } else + update_needed = false; + + if (update_needed) + connman_network_update(connman_network); } static void network_associated(GSupplicantNetwork *network) @@ -2819,6 +2946,10 @@ static void network_associated(GSupplicantNetwork *network) if (!wifi) return; + /* P2P networks must not be treated as WiFi networks */ + if (wifi->p2p_connecting || wifi->p2p_device) + return; + identifier = g_supplicant_network_get_identifier(network); connman_network = connman_device_get_network(wifi->device, identifier); @@ -2853,6 +2984,32 @@ static void network_associated(GSupplicantNetwork *network) interface_state(interface); } +static void sta_authorized(GSupplicantInterface *interface, + const char *addr) +{ + struct wifi_data *wifi = g_supplicant_interface_get_data(interface); + + DBG("wifi %p station %s authorized", wifi, addr); + + if (!wifi || !wifi->tethering) + return; + + __connman_tethering_client_register(addr); +} + +static void sta_deauthorized(GSupplicantInterface *interface, + const char *addr) +{ + struct wifi_data *wifi = g_supplicant_interface_get_data(interface); + + DBG("wifi %p station %s deauthorized", wifi, addr); + + if (!wifi || !wifi->tethering) + return; + + __connman_tethering_client_unregister(addr); +} + static void apply_peer_services(GSupplicantPeer *peer, struct connman_peer *connman_peer) { @@ -3073,6 +3230,8 @@ static const GSupplicantCallbacks callbacks = { .network_removed = network_removed, .network_changed = network_changed, .network_associated = network_associated, + .sta_authorized = sta_authorized, + .sta_deauthorized = sta_deauthorized, .peer_found = peer_found, .peer_lost = peer_lost, .peer_changed = peer_changed, -- cgit v1.2.3