summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSeonah Moon <seonah1.moon@samsung.com>2018-01-23 14:50:50 +0900
committerSeonah Moon <seonah1.moon@samsung.com>2018-01-23 14:50:55 +0900
commit30602f521a85820a9f6b7ac04876400e00c68b15 (patch)
treef035a4fcc014a034f3b492886d1e8395f327fd25 /src
parenta079cfe6f815f8c69055de834d1ccbdf1fd94ba7 (diff)
parent9362752a471a5c892d679548fbf2828d5fc5684b (diff)
downloadconnman-30602f521a85820a9f6b7ac04876400e00c68b15.tar.gz
connman-30602f521a85820a9f6b7ac04876400e00c68b15.tar.bz2
connman-30602f521a85820a9f6b7ac04876400e00c68b15.zip
Updated connman to version 1.35
Change-Id: I13526fbf80296a79be15548fc226a308941ac9ec Signed-off-by: Taesub Kim <taesub.kim@samsung.com>
Diffstat (limited to 'src')
-rwxr-xr-xsrc/6to4.c2
-rwxr-xr-xsrc/agent-connman.c114
-rwxr-xr-xsrc/agent.c17
-rwxr-xr-xsrc/bridge.c2
-rwxr-xr-xsrc/config.c148
-rwxr-xr-xsrc/connection.c93
-rwxr-xr-xsrc/connman.h54
-rw-r--r--src/connmand-wait-online.c461
-rwxr-xr-xsrc/device.c48
-rwxr-xr-xsrc/dhcp.c95
-rwxr-xr-xsrc/dhcpv6.c17
-rwxr-xr-xsrc/dnsproxy.c230
-rw-r--r--[-rwxr-xr-x]src/firewall-iptables.c (renamed from src/firewall.c)265
-rw-r--r--src/firewall-nftables.c1133
-rwxr-xr-xsrc/inet.c357
-rwxr-xr-xsrc/ipconfig.c105
-rwxr-xr-xsrc/ippool.c45
-rwxr-xr-xsrc/iptables.c89
-rwxr-xr-xsrc/log.c2
-rwxr-xr-xsrc/main.c87
-rwxr-xr-xsrc/main.conf20
-rwxr-xr-xsrc/nat.c64
-rwxr-xr-xsrc/network.c188
-rwxr-xr-xsrc/ntp.c205
-rwxr-xr-xsrc/peer.c9
-rwxr-xr-xsrc/peer_service.c3
-rwxr-xr-xsrc/provider.c15
-rwxr-xr-xsrc/proxy.c2
-rwxr-xr-xsrc/resolver.c78
-rwxr-xr-xsrc/rfkill.c2
-rwxr-xr-xsrc/rtnl.c16
-rwxr-xr-xsrc/service.c1086
-rwxr-xr-xsrc/session.c427
-rwxr-xr-xsrc/stats.c50
-rwxr-xr-xsrc/storage.c2
-rwxr-xr-xsrc/task.c3
-rwxr-xr-xsrc/technology.c97
-rwxr-xr-xsrc/tethering.c18
-rwxr-xr-xsrc/timeserver.c13
-rwxr-xr-xsrc/util.c15
-rwxr-xr-xsrc/wispr.c7
-rwxr-xr-xsrc/wpad.c9
42 files changed, 4353 insertions, 1340 deletions
diff --git a/src/6to4.c b/src/6to4.c
index 0e3a7a15..71a28827 100755
--- a/src/6to4.c
+++ b/src/6to4.c
@@ -63,7 +63,7 @@ static int tunnel_create(struct in_addr *addr)
{
struct ip_tunnel_parm p;
struct ifreq ifr;
- int fd = -1;
+ int fd;
int ret;
/* ip tunnel add tun6to4 mode sit remote any local 1.2.3.4 ttl 64 */
diff --git a/src/agent-connman.c b/src/agent-connman.c
index 177cbe0a..e4850a8f 100755
--- a/src/agent-connman.c
+++ b/src/agent-connman.c
@@ -100,73 +100,101 @@ static void request_input_passphrase_reply(DBusMessage *reply, void *user_data)
DBusMessageIter entry, value;
dbus_message_iter_recurse(&dict, &entry);
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
dbus_message_iter_get_basic(&entry, &key);
if (g_str_equal(key, "Identity")) {
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
- != DBUS_TYPE_VARIANT)
+ != DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
+
dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
+ break;
+ }
+
dbus_message_iter_get_basic(&value, &identity);
} else if (g_str_equal(key, "Passphrase")) {
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
- != DBUS_TYPE_VARIANT)
+ != DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
+
dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
+ break;
+ }
+
dbus_message_iter_get_basic(&value, &passphrase);
} else if (g_str_equal(key, "WPS")) {
- wps = true;
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
- != DBUS_TYPE_VARIANT)
+ != DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
+
dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
+ break;
+ }
+
+ wps = true;
dbus_message_iter_get_basic(&value, &wpspin);
break;
} else if (g_str_equal(key, "Name")) {
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
- != DBUS_TYPE_VARIANT)
+ != DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
+
dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
+ break;
+ }
+
dbus_message_iter_get_basic(&value, &name);
name_len = strlen(name);
} else if (g_str_equal(key, "SSID")) {
-#if defined TIZEN_EXT
- DBusMessageIter array;
-#endif
+ DBusMessageIter array_iter;
+
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
- != DBUS_TYPE_VARIANT)
- break;
-#if defined TIZEN_EXT
- dbus_message_iter_recurse(&entry, &array);
- if (dbus_message_iter_get_arg_type(&array)
- != DBUS_TYPE_ARRAY)
- break;
- dbus_message_iter_recurse(&array, &value);
- if (dbus_message_iter_get_arg_type(&value)
- != DBUS_TYPE_BYTE)
+ != DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
-#else
-
+ }
dbus_message_iter_recurse(&entry, &value);
if (dbus_message_iter_get_arg_type(&value)
- != DBUS_TYPE_VARIANT)
+ != DBUS_TYPE_ARRAY) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
- if (dbus_message_iter_get_element_type(&value)
- != DBUS_TYPE_VARIANT)
+ }
+ dbus_message_iter_recurse(&value, &array_iter);
+ if (dbus_message_iter_get_arg_type(&array_iter)
+ != DBUS_TYPE_BYTE) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
-#endif
- dbus_message_iter_get_fixed_array(&value, &name,
+ }
+ dbus_message_iter_get_fixed_array(&array_iter, &name,
&name_len);
}
dbus_message_iter_next(&dict);
@@ -417,17 +445,33 @@ static void request_input_login_reply(DBusMessage *reply, void *user_data)
if (g_str_equal(key, "Username")) {
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
- != DBUS_TYPE_VARIANT)
+ != DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
+
dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
+ break;
+ }
+
dbus_message_iter_get_basic(&value, &username);
} else if (g_str_equal(key, "Password")) {
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry) !=
- DBUS_TYPE_VARIANT)
+ DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
+
dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
+ break;
+ }
+
dbus_message_iter_get_basic(&value, &password);
}
@@ -723,8 +767,10 @@ static void request_peer_authorization_reply(DBusMessage *reply,
DBusMessageIter entry, value;
dbus_message_iter_recurse(&dict, &entry);
- if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
dbus_message_iter_get_basic(&entry, &key);
@@ -733,9 +779,17 @@ static void request_peer_authorization_reply(DBusMessage *reply,
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry)
- != DBUS_TYPE_VARIANT)
+ != DBUS_TYPE_VARIANT) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
break;
+ }
+
dbus_message_iter_recurse(&entry, &value);
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) {
+ error = CONNMAN_ERROR_INTERFACE ".InvalidArguments";
+ break;
+ }
+
dbus_message_iter_get_basic(&value, &wpspin);
break;
}
diff --git a/src/agent.c b/src/agent.c
index bdeb0e71..8f7b19ba 100755
--- a/src/agent.c
+++ b/src/agent.c
@@ -165,12 +165,17 @@ static int send_cancel_request(struct connman_agent *agent,
struct connman_agent_request *request)
{
DBusMessage *message;
+ const char *interface = NULL;
- DBG("send cancel req to %s %s", agent->owner, agent->path);
+ if (request && request->driver)
+ interface = request->driver->interface;
+
+ DBG("send cancel req to %s %s iface %s", agent->owner, agent->path,
+ interface);
message = dbus_message_new_method_call(agent->owner,
agent->path,
- request->driver->interface,
+ interface,
"Cancel");
if (!message) {
connman_error("Couldn't allocate D-Bus message");
@@ -519,12 +524,12 @@ void connman_agent_cancel(void *user_context)
user_context) {
DBG("cancel pending %p", request);
+ agent->queue = g_list_delete_link(agent->queue,
+ list);
+
request->callback(NULL, request->user_data);
agent_request_free(request);
-
- agent->queue = g_list_delete_link(agent->queue,
- list);
}
list = next;
@@ -581,7 +586,7 @@ static void agent_release(struct connman_agent *agent, const char *interface)
message = dbus_message_new_method_call(agent->owner, agent->path,
interface, "Release");
- if (message == NULL) {
+ if (!message) {
connman_error("Couldn't allocate D-Bus message");
return;
}
diff --git a/src/bridge.c b/src/bridge.c
index ba200969..cd2d9cee 100755
--- a/src/bridge.c
+++ b/src/bridge.c
@@ -56,7 +56,7 @@ static int set_forward_delay(const char *name, unsigned int delay)
if (!f)
return -errno;
- fprintf(f, "%d", delay);
+ fprintf(f, "%u", delay);
fclose(f);
diff --git a/src/config.c b/src/config.c
index 25dd1748..75cd717f 100755
--- a/src/config.c
+++ b/src/config.c
@@ -45,7 +45,12 @@ struct connman_config_service {
unsigned int ssid_len;
char *eap;
char *identity;
+ char *anonymous_identity;
char *ca_cert_file;
+ char *subject_match;
+ char *altsubject_match;
+ char *domain_suffix_match;
+ char *domain_match;
char *client_cert_file;
char *private_key_file;
char *private_key_passphrase;
@@ -98,6 +103,11 @@ static bool cleanup = false;
#define SERVICE_KEY_PRV_KEY_PASS "PrivateKeyPassphrase"
#define SERVICE_KEY_PRV_KEY_PASS_TYPE "PrivateKeyPassphraseType"
#define SERVICE_KEY_IDENTITY "Identity"
+#define SERVICE_KEY_ANONYMOUS_IDENTITY "AnonymousIdentity"
+#define SERVICE_KEY_SUBJECT_MATCH "SubjectMatch"
+#define SERVICE_KEY_ALT_SUBJECT_MATCH "AltSubjectMatch"
+#define SERVICE_KEY_DOMAIN_SUFF_MATCH "DomainSuffixMatch"
+#define SERVICE_KEY_DOMAIN_MATCH "DomainMatch"
#define SERVICE_KEY_PHASE2 "Phase2"
#define SERVICE_KEY_PASSPHRASE "Passphrase"
#define SERVICE_KEY_SECURITY "Security"
@@ -129,6 +139,11 @@ static const char *service_possible_keys[] = {
SERVICE_KEY_PRV_KEY_PASS,
SERVICE_KEY_PRV_KEY_PASS_TYPE,
SERVICE_KEY_IDENTITY,
+ SERVICE_KEY_ANONYMOUS_IDENTITY,
+ SERVICE_KEY_SUBJECT_MATCH,
+ SERVICE_KEY_ALT_SUBJECT_MATCH,
+ SERVICE_KEY_DOMAIN_SUFF_MATCH,
+ SERVICE_KEY_DOMAIN_MATCH,
SERVICE_KEY_PHASE2,
SERVICE_KEY_PASSPHRASE,
SERVICE_KEY_SECURITY,
@@ -220,7 +235,12 @@ free_only:
g_free(config_service->ssid);
g_free(config_service->eap);
g_free(config_service->identity);
+ g_free(config_service->anonymous_identity);
g_free(config_service->ca_cert_file);
+ g_free(config_service->subject_match);
+ g_free(config_service->altsubject_match);
+ g_free(config_service->domain_suffix_match);
+ g_free(config_service->domain_match);
g_free(config_service->client_cert_file);
g_free(config_service->private_key_file);
g_free(config_service->private_key_passphrase);
@@ -655,6 +675,41 @@ static bool load_service(GKeyFile *keyfile, const char *group,
service->identity = str;
}
+ str = __connman_config_get_string(keyfile, group,
+ SERVICE_KEY_ANONYMOUS_IDENTITY, NULL);
+ if (str) {
+ g_free(service->anonymous_identity);
+ service->anonymous_identity = str;
+ }
+
+ str = __connman_config_get_string(keyfile, group,
+ SERVICE_KEY_SUBJECT_MATCH, NULL);
+ if (str) {
+ g_free(service->subject_match);
+ service->subject_match = str;
+ }
+
+ str = __connman_config_get_string(keyfile, group,
+ SERVICE_KEY_ALT_SUBJECT_MATCH, NULL);
+ if (str) {
+ g_free(service->altsubject_match);
+ service->altsubject_match = str;
+ }
+
+ str = __connman_config_get_string(keyfile, group,
+ SERVICE_KEY_DOMAIN_SUFF_MATCH, NULL);
+ if (str) {
+ g_free(service->domain_suffix_match);
+ service->domain_suffix_match = str;
+ }
+
+ str = __connman_config_get_string(keyfile, group,
+ SERVICE_KEY_DOMAIN_MATCH, NULL);
+ if (str) {
+ g_free(service->domain_match);
+ service->domain_match = str;
+ }
+
str = __connman_config_get_string(keyfile, group, SERVICE_KEY_PHASE2, NULL);
if (str) {
g_free(service->phase2);
@@ -701,7 +756,18 @@ static bool load_service(GKeyFile *keyfile, const char *group,
} else
service->security = CONNMAN_SERVICE_SECURITY_PSK;
- }
+ } else if (str) {
+
+ if (security != CONNMAN_SERVICE_SECURITY_NONE) {
+ connman_info("Mismatch no security and "
+ "setting %s = %s",
+ SERVICE_KEY_SECURITY, str);
+ }
+ service->security = CONNMAN_SERVICE_SECURITY_NONE;
+ } else
+ service->security = CONNMAN_SERVICE_SECURITY_NONE;
+
+ g_free(str);
service->config_ident = g_strdup(config->ident);
service->config_entry = g_strdup_printf("service_%s", service->ident);
@@ -894,10 +960,10 @@ static void config_notify_handler(struct inotify_event *event,
return;
}
- if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO)
+ if (event->mask & (IN_CREATE | IN_MOVED_TO))
create_config(ident);
- if (event->mask & IN_MODIFY) {
+ if (event->mask & (IN_MODIFY | IN_MOVED_TO)) {
struct connman_config *config;
config = g_hash_table_lookup(config_table, ident);
@@ -919,7 +985,7 @@ static void config_notify_handler(struct inotify_event *event,
}
}
- if (event->mask & IN_DELETE)
+ if (event->mask & (IN_DELETE | IN_MOVED_FROM))
g_hash_table_remove(config_table, ident);
}
@@ -956,6 +1022,11 @@ char *__connman_config_get_string(GKeyFile *key_file,
if (!str)
return NULL;
+ /* passphrases can have spaces in the end */
+ if (!g_strcmp0(key, SERVICE_KEY_PASSPHRASE) ||
+ !g_strcmp0(key, SERVICE_KEY_PRV_KEY_PASS))
+ return str;
+
return g_strchomp(str);
}
@@ -1028,10 +1099,30 @@ static void provision_service_wifi(struct connman_config_service *config,
__connman_service_set_string(service, "Identity",
config->identity);
+ if (config->anonymous_identity)
+ __connman_service_set_string(service, "AnonymousIdentity",
+ config->anonymous_identity);
+
if (config->ca_cert_file)
__connman_service_set_string(service, "CACertFile",
config->ca_cert_file);
+ if (config->subject_match)
+ __connman_service_set_string(service, "SubjectMatch",
+ config->subject_match);
+
+ if (config->altsubject_match)
+ __connman_service_set_string(service, "AltSubjectMatch",
+ config->altsubject_match);
+
+ if (config->domain_suffix_match)
+ __connman_service_set_string(service, "DomainSuffixMatch",
+ config->domain_suffix_match);
+
+ if (config->domain_match)
+ __connman_service_set_string(service, "DomainMatch",
+ config->domain_match);
+
if (config->client_cert_file)
__connman_service_set_string(service, "ClientCertFile",
config->client_cert_file);
@@ -1333,7 +1424,7 @@ static int try_provision_service(struct connman_config_service *config,
virtual->service = service;
virtual->vfile = config->virtual_file;
- g_timeout_add(0, remove_virtual_config, virtual);
+ g_idle_add(remove_virtual_config, virtual);
return 0;
}
@@ -1353,22 +1444,35 @@ static int try_provision_service(struct connman_config_service *config,
return 0;
}
+static int
+find_and_provision_service_from_config(struct connman_service *service,
+ struct connman_config *config)
+{
+ GHashTableIter iter;
+ gpointer value, key;
+
+ g_hash_table_iter_init(&iter, config->service_table);
+ while (g_hash_table_iter_next(&iter, &key,
+ &value)) {
+ if (!try_provision_service(value, service))
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
static int find_and_provision_service(struct connman_service *service)
{
- GHashTableIter iter, iter_service;
- gpointer value, key, value_service, key_service;
+ GHashTableIter iter;
+ gpointer value, key;
g_hash_table_iter_init(&iter, config_table);
while (g_hash_table_iter_next(&iter, &key, &value)) {
struct connman_config *config = value;
- g_hash_table_iter_init(&iter_service, config->service_table);
- while (g_hash_table_iter_next(&iter_service, &key_service,
- &value_service)) {
- if (!try_provision_service(value_service, service))
- return 0;
- }
+ if (!find_and_provision_service_from_config(service, config))
+ return 0;
}
return -ENOENT;
@@ -1459,7 +1563,7 @@ int __connman_config_provision_service_ident(struct connman_service *service,
}
}
- find_and_provision_service(service);
+ find_and_provision_service_from_config(service, config);
}
return ret;
@@ -1489,7 +1593,7 @@ int connman_config_provision_mutable_service(GKeyFile *keyfile)
{
struct connman_config_service *service_config;
struct connman_config *config;
- char *vfile, *group;
+ char *vfile, *group = NULL;
char rstr[11];
DBG("");
@@ -1525,13 +1629,14 @@ int connman_config_provision_mutable_service(GKeyFile *keyfile)
if (g_strcmp0(service_config->type, "wifi") == 0)
__connman_device_request_scan(CONNMAN_SERVICE_TYPE_WIFI);
+ g_free(group);
return 0;
error:
DBG("Could not proceed");
g_hash_table_remove(config_table, vfile);
g_free(vfile);
-
+ g_free(group);
return -EINVAL;
}
@@ -1545,13 +1650,16 @@ struct connman_config_entry **connman_config_get_entries(const char *type)
g_hash_table_iter_init(&iter_file, config_table);
while (g_hash_table_iter_next(&iter_file, &key, &value)) {
struct connman_config *config_file = value;
+ struct connman_config_entry **tmp_entries = entries;
count = g_hash_table_size(config_file->service_table);
entries = g_try_realloc(entries, (i + count + 1) *
sizeof(struct connman_config_entry *));
- if (!entries)
+ if (!entries) {
+ g_free(tmp_entries);
return NULL;
+ }
g_hash_table_iter_init(&iter_config,
config_file->service_table);
@@ -1584,10 +1692,14 @@ struct connman_config_entry **connman_config_get_entries(const char *type)
}
if (entries) {
+ struct connman_config_entry **tmp_entries = entries;
+
entries = g_try_realloc(entries, (i + 1) *
sizeof(struct connman_config_entry *));
- if (!entries)
+ if (!entries) {
+ g_free(tmp_entries);
return NULL;
+ }
entries[i] = NULL;
diff --git a/src/connection.c b/src/connection.c
index 4389d587..64d48b7d 100755
--- a/src/connection.c
+++ b/src/connection.c
@@ -46,7 +46,6 @@ struct gateway_config {
struct gateway_data {
int index;
struct connman_service *service;
- unsigned int order;
struct gateway_config *ipv4_gateway;
struct gateway_config *ipv6_gateway;
bool default_checked;
@@ -381,8 +380,6 @@ static struct gateway_data *add_gateway(struct connman_service *service,
data->service = service;
- data->order = __connman_service_get_order(service);
-
/*
* If the service is already in the hash, then we
* must not replace it blindly but disable the gateway
@@ -558,25 +555,13 @@ static void unset_default_gateway(struct gateway_data *data,
static struct gateway_data *find_default_gateway(void)
{
- struct gateway_data *found = NULL;
- unsigned int order = 0;
- GHashTableIter iter;
- gpointer value, key;
-
- g_hash_table_iter_init(&iter, gateway_hash);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- struct gateway_data *data = value;
-
- if (!found || data->order > order) {
- found = data;
- order = data->order;
+ struct connman_service *service;
- DBG("default %p order %d", found, order);
- }
- }
+ service = __connman_service_get_default();
+ if (!service)
+ return NULL;
- return found;
+ return g_hash_table_lookup(gateway_hash, service);
}
static bool choose_default_gateway(struct gateway_data *data,
@@ -589,37 +574,35 @@ static bool choose_default_gateway(struct gateway_data *data,
* this one as default. If the other one is already active
* we mark this one as non default.
*/
- if (data->ipv4_gateway) {
- if (candidate->ipv4_gateway &&
- !candidate->ipv4_gateway->active) {
+ if (data->ipv4_gateway && candidate->ipv4_gateway) {
+
+ if (!candidate->ipv4_gateway->active) {
DBG("ipv4 downgrading %p", candidate);
unset_default_gateway(candidate,
CONNMAN_IPCONFIG_TYPE_IPV4);
}
- if (candidate->ipv4_gateway &&
- candidate->ipv4_gateway->active &&
- candidate->order > data->order) {
+
+ if (candidate->ipv4_gateway->active &&
+ __connman_service_compare(candidate->service,
+ data->service) < 0) {
DBG("ipv4 downgrading this %p", data);
- unset_default_gateway(data,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ unset_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
downgraded = true;
}
}
- if (data->ipv6_gateway) {
- if (candidate->ipv6_gateway &&
- !candidate->ipv6_gateway->active) {
+ if (data->ipv6_gateway && candidate->ipv6_gateway) {
+ if (!candidate->ipv6_gateway->active) {
DBG("ipv6 downgrading %p", candidate);
unset_default_gateway(candidate,
CONNMAN_IPCONFIG_TYPE_IPV6);
}
- if (candidate->ipv6_gateway &&
- candidate->ipv6_gateway->active &&
- candidate->order > data->order) {
+ if (candidate->ipv6_gateway->active &&
+ __connman_service_compare(candidate->service,
+ data->service) < 0) {
DBG("ipv6 downgrading this %p", data);
- unset_default_gateway(data,
- CONNMAN_IPCONFIG_TYPE_IPV6);
+ unset_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV6);
downgraded = true;
}
}
@@ -762,40 +745,6 @@ static struct gateway_data *find_active_gateway(void)
return NULL;
}
-static void update_order(void)
-{
- GHashTableIter iter;
- gpointer value, key;
-
- DBG("");
-
- g_hash_table_iter_init(&iter, gateway_hash);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- struct gateway_data *data = value;
-
- data->order = __connman_service_get_order(data->service);
- }
-}
-
-void __connman_connection_gateway_activate(struct connman_service *service,
- enum connman_ipconfig_type type)
-{
- struct gateway_data *data = NULL;
-
- data = g_hash_table_lookup(gateway_hash, service);
- if (!data)
- return;
-
- DBG("gateway %p/%p type %d", data->ipv4_gateway,
- data->ipv6_gateway, type);
-
- if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
- data->ipv4_gateway->active = true;
- else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
- data->ipv6_gateway->active = true;
-}
-
static void add_host_route(int family, int index, const char *gateway,
enum connman_service_type service_type)
{
@@ -1090,12 +1039,8 @@ bool __connman_connection_update_gateway(void)
if (!gateway_hash)
return updated;
- update_order();
-
default_gateway = find_default_gateway();
- __connman_service_update_ordering();
-
DBG("default %p", default_gateway);
/*
diff --git a/src/connman.h b/src/connman.h
index 57cfc872..4125463b 100755
--- a/src/connman.h
+++ b/src/connman.h
@@ -244,10 +244,14 @@ int __connman_inet_del_default_from_table(uint32_t table_id, int ifindex, const
int __connman_inet_get_address_netmask(int ifindex,
struct sockaddr_in *address, struct sockaddr_in *netmask);
+bool __connman_inet_isrootnfs_device(const char *devname);
+char **__connman_inet_get_pnp_nameservers(const char *pnp_file);
+
#include <connman/resolver.h>
int __connman_resolver_init(gboolean dnsproxy);
void __connman_resolver_cleanup(void);
+void __connman_resolver_append_fallback_nameservers(void);
int __connman_resolvfile_append(int index, const char *domain, const char *server);
int __connman_resolvfile_remove(int index, const char *domain, const char *server);
int __connman_resolver_redo_servers(int index);
@@ -511,8 +515,6 @@ void __connman_connection_gateway_remove(struct connman_service *service,
int __connman_connection_get_vpn_index(int phy_index);
bool __connman_connection_update_gateway(void);
-void __connman_connection_gateway_activate(struct connman_service *service,
- enum connman_ipconfig_type type);
int __connman_ntp_start(char *server);
void __connman_ntp_stop();
@@ -648,7 +650,7 @@ int __connman_tethering_init(void);
void __connman_tethering_cleanup(void);
const char *__connman_tethering_get_bridge(void);
-void __connman_tethering_set_enabled(void);
+int __connman_tethering_set_enabled(void);
void __connman_tethering_set_disabled(void);
int __connman_private_network_request(DBusMessage *msg, const char *owner);
@@ -671,7 +673,8 @@ int __connman_provider_indicate_state(struct connman_provider *provider,
enum connman_provider_state state);
int __connman_provider_indicate_error(struct connman_provider *provider,
enum connman_provider_error error);
-int __connman_provider_connect(struct connman_provider *provider);
+int __connman_provider_connect(struct connman_provider *provider,
+ const char *dbus_sender);
int __connman_provider_remove_by_path(const char *path);
void __connman_provider_cleanup(void);
int __connman_provider_init(void);
@@ -693,6 +696,9 @@ enum connman_dnsconfig_method {
};
#endif
+int __connman_service_compare(const struct connman_service *a,
+ const struct connman_service *b);
+
struct connman_service *__connman_service_lookup_from_index(int index);
struct connman_service *__connman_service_lookup_from_ident(const char *identifier);
struct connman_service *__connman_service_create_from_network(struct connman_network *network);
@@ -710,6 +716,8 @@ struct connman_ipconfig *__connman_service_get_ip6config(
struct connman_service *service);
struct connman_ipconfig *__connman_service_get_ipconfig(
struct connman_service *service, int family);
+void __connman_service_notify_ipv4_configuration(
+ struct connman_service *service);
bool __connman_service_is_connected_state(struct connman_service *service,
enum connman_ipconfig_type type);
const char *__connman_service_get_ident(struct connman_service *service);
@@ -717,7 +725,6 @@ const char *__connman_service_get_path(struct connman_service *service);
const char *__connman_service_get_name(struct connman_service *service);
unsigned int __connman_service_get_order(struct connman_service *service);
enum connman_service_state __connman_service_get_state(struct connman_service *service);
-void __connman_service_update_ordering(void);
struct connman_network *__connman_service_get_network(struct connman_service *service);
enum connman_service_security __connman_service_get_security(struct connman_service *service);
const char *__connman_service_get_phase2(struct connman_service *service);
@@ -842,11 +849,23 @@ void __connman_service_set_proxy_autoconfig(struct connman_service *service,
void __connman_service_set_identity(struct connman_service *service,
const char *identity);
+void __connman_service_set_anonymous_identity(struct connman_service *service,
+ const char *anonymous_identity);
+void __connman_service_set_subject_match(struct connman_service *service,
+ const char *subject_match);
+void __connman_service_set_altsubject_match(struct connman_service *service,
+ const char *altsubject_match);
+void __connman_service_set_domain_suffix_match(struct connman_service *service,
+ const char *domain_suffix_match);
+void __connman_service_set_domain_match(struct connman_service *service,
+ const char *domain_match);
void __connman_service_set_agent_identity(struct connman_service *service,
const char *agent_identity);
int __connman_service_set_passphrase(struct connman_service *service,
const char *passphrase);
const char *__connman_service_get_passphrase(struct connman_service *service);
+int __connman_service_check_passphrase(enum connman_service_security security,
+ const char *passphrase);
int __connman_service_reset_ipconfig(struct connman_service *service,
enum connman_ipconfig_type type, DBusMessageIter *array,
enum connman_service_state *new_state);
@@ -939,6 +958,11 @@ unsigned int __connman_rtnl_update_interval_remove(unsigned int interval);
int __connman_rtnl_request_update(void);
int __connman_rtnl_send(const void *buf, size_t len);
+#if defined TIZEN_EXT
+void rtnl_nameserver_add_all(struct connman_service *service,
+ enum connman_ipconfig_type type);
+#endif
+
bool __connman_session_policy_autoconnect(enum connman_service_connect_reason reason);
int __connman_session_create(DBusMessage *msg);
@@ -1063,13 +1087,19 @@ struct firewall_context;
struct firewall_context *__connman_firewall_create(void);
void __connman_firewall_destroy(struct firewall_context *ctx);
-int __connman_firewall_add_rule(struct firewall_context *ctx,
- const char *table,
- const char *chain,
- const char *rule_fmt, ...);
-int __connman_firewall_enable(struct firewall_context *ctx);
-int __connman_firewall_disable(struct firewall_context *ctx);
-bool __connman_firewall_is_up(void);
+int __connman_firewall_enable_nat(struct firewall_context *ctx,
+ char *address, unsigned char prefixlen,
+ char *interface);
+int __connman_firewall_disable_nat(struct firewall_context *ctx);
+int __connman_firewall_enable_snat(struct firewall_context *ctx,
+ int index, const char *ifname,
+ const char *addr);
+int __connman_firewall_disable_snat(struct firewall_context *ctx);
+int __connman_firewall_enable_marking(struct firewall_context *ctx,
+ enum connman_session_id_type id_type,
+ char *id, const char *src_ip,
+ uint32_t mark);
+int __connman_firewall_disable_marking(struct firewall_context *ctx);
int __connman_firewall_init(void);
void __connman_firewall_cleanup(void);
diff --git a/src/connmand-wait-online.c b/src/connmand-wait-online.c
new file mode 100644
index 00000000..2711d56f
--- /dev/null
+++ b/src/connmand-wait-online.c
@@ -0,0 +1,461 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <dbus/dbus.h>
+
+#include <gdbus.h>
+#include <connman/dbus.h>
+
+static DBusConnection *connection;
+static GMainLoop *main_loop;
+static int timeout = 0;
+static int exit_value = 0;
+
+static gboolean option_version = FALSE;
+static gchar *option_interface = NULL;
+static gchar *option_ignore = NULL;
+static gint option_timeout = 120;
+
+struct devices {
+ char **interface;
+ char **ignore;
+};
+
+static GOptionEntry options[] = {
+ { "interface", 'i', 0, G_OPTION_ARG_STRING, &option_interface,
+ "Specify networking device or interface", "DEV" },
+ { "ignore", 'I', 0, G_OPTION_ARG_STRING, &option_ignore,
+ "Specify networking device or interface to ignore", "DEV" },
+ { "timeout", 0, 0, G_OPTION_ARG_INT, &option_timeout,
+ "Time to wait for network going online. Default is 120 seconds.",
+ "seconds" },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+ "Show version information and exit" },
+ { NULL },
+};
+
+static bool compare_interface(const char *interface, struct devices *devices)
+{
+ int i;
+
+ if (!interface || !devices)
+ return false;
+
+ for (i = 0; devices->ignore && devices->ignore[i]; i++)
+ if (!strcmp(interface, devices->ignore[i]))
+ return false;
+
+ if (!devices->interface)
+ return true;
+
+ for (i = 0; devices->interface[i]; i++)
+ if (!strcmp(interface, devices->interface[i]))
+ return true;
+
+ return false;
+}
+
+static bool state_online(DBusMessageIter *iter)
+{
+ char *str;
+ DBusMessageIter variant;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(iter, &str);
+ if (strcmp(str, "State"))
+ return false;
+
+ dbus_message_iter_next(iter);
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+ return false;
+
+ dbus_message_iter_recurse(iter, &variant);
+
+ if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_STRING)
+ return false;
+
+ dbus_message_iter_get_basic(&variant, &str);
+ if (strcmp(str, "ready") && strcmp(str, "online"))
+ return false;
+
+ return true;
+}
+
+static bool service_properties_online(DBusMessageIter *array_entry,
+ struct devices *devices)
+{
+ bool interface = !devices;
+ bool state = false;
+ DBusMessageIter dict, dict_entry, variant, eth_array, eth_dict,
+ eth_variant;
+ char *str;
+
+ for (dbus_message_iter_recurse(array_entry, &dict);
+ dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY;
+ dbus_message_iter_next(&dict)) {
+
+ dbus_message_iter_recurse(&dict, &dict_entry);
+ if (dbus_message_iter_get_arg_type(&dict_entry)
+ != DBUS_TYPE_STRING)
+ continue;
+
+ if (state_online(&dict_entry)) {
+ state = true;
+ continue;
+ }
+
+ dbus_message_iter_recurse(&dict, &dict_entry);
+
+ dbus_message_iter_get_basic(&dict_entry, &str);
+
+ if (devices && !strcmp(str, "Ethernet")) {
+ dbus_message_iter_next(&dict_entry);
+
+ if (dbus_message_iter_get_arg_type(&dict_entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+
+ dbus_message_iter_recurse(&dict_entry, &variant);
+ if (dbus_message_iter_get_arg_type(&variant)
+ != DBUS_TYPE_ARRAY)
+ break;
+
+ for (dbus_message_iter_recurse(&variant, &eth_array);
+ dbus_message_iter_get_arg_type(&eth_array)
+ == DBUS_TYPE_DICT_ENTRY;
+ dbus_message_iter_next(&eth_array)) {
+
+ dbus_message_iter_recurse(&eth_array, &eth_dict);
+
+ if (dbus_message_iter_get_arg_type(&eth_dict)
+ != DBUS_TYPE_STRING)
+ continue;
+
+ dbus_message_iter_get_basic(&eth_dict, &str);
+ if (!strcmp(str, "Interface")) {
+
+ dbus_message_iter_next(&eth_dict);
+ if (dbus_message_iter_get_arg_type(&eth_dict)
+ != DBUS_TYPE_VARIANT)
+ break;
+
+ dbus_message_iter_recurse(&eth_dict,
+ &eth_variant);
+ if (dbus_message_iter_get_arg_type(&eth_variant)
+ != DBUS_TYPE_STRING)
+ break;
+
+ dbus_message_iter_get_basic(&eth_variant,
+ &str);
+ interface = compare_interface(str,
+ devices);
+
+ break;
+ }
+ }
+ }
+
+ if (state && interface) {
+ g_main_loop_quit(main_loop);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void services_dict_online(DBusMessageIter *iter, struct devices *devices)
+{
+ DBusMessageIter array, array_entry;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return;
+
+ for (dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT;
+ dbus_message_iter_next(&array)) {
+
+ dbus_message_iter_recurse(&array, &array_entry);
+
+ if (dbus_message_iter_get_arg_type(&array_entry) !=
+ DBUS_TYPE_OBJECT_PATH)
+ break;
+
+ dbus_message_iter_next(&array_entry);
+
+ if (dbus_message_iter_get_arg_type(&array_entry) !=
+ DBUS_TYPE_ARRAY)
+ continue;
+
+ if (service_properties_online(&array_entry, devices))
+ break;
+ }
+}
+
+static void manager_get_services_return(DBusPendingCall *call,
+ void *user_data)
+{
+ struct devices *devices = user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
+ goto fail;
+
+ if (!dbus_message_iter_init(reply, &iter))
+ goto fail;
+
+ services_dict_online(&iter, devices);
+
+fail:
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static void manager_get_services(struct devices *devices)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(CONNMAN_SERVICE,
+ CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE,
+ "GetServices");
+ if (!message)
+ return;
+
+ if (!dbus_connection_send_with_reply(connection, message, &call, -1))
+ goto fail;
+
+ if (!call)
+ goto fail;
+
+ dbus_pending_call_set_notify(call, manager_get_services_return,
+ devices, NULL);
+
+fail:
+ dbus_message_unref(message);
+}
+
+static void manager_properties_online(DBusMessageIter *iter,
+ struct devices *devices)
+{
+ DBusMessageIter array, dict_entry;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return;
+
+ for (dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY;
+ dbus_message_iter_next(&array)) {
+
+ dbus_message_iter_recurse(&array, &dict_entry);
+
+ if (state_online(&dict_entry)) {
+ if (devices)
+ manager_get_services(devices);
+ else
+ g_main_loop_quit(main_loop);
+
+ break;
+ }
+ }
+}
+
+static void manager_get_properties_return(DBusPendingCall *call, void *user_data)
+{
+ struct devices *devices = user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+
+ reply = dbus_pending_call_steal_reply(call);
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
+ goto fail;
+
+ if (!dbus_message_iter_init(reply, &iter))
+ goto fail;
+
+ manager_properties_online(&iter, devices);
+
+fail:
+ dbus_message_unref(reply);
+ dbus_pending_call_unref(call);
+}
+
+static void manager_get_properties(struct devices *devices)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(CONNMAN_SERVICE,
+ CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE,
+ "GetProperties");
+ if (!message)
+ return;
+
+ if (!dbus_connection_send_with_reply(connection, message, &call, -1))
+ goto fail;
+
+ if (!call)
+ goto fail;
+
+ dbus_pending_call_set_notify(call, manager_get_properties_return,
+ devices, NULL);
+
+fail:
+ dbus_message_unref(message);
+}
+
+static DBusHandlerResult manager_property_changed(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct devices *devices = user_data;
+ DBusMessageIter iter;
+
+ if (dbus_message_is_signal(message, CONNMAN_MANAGER_INTERFACE,
+ "PropertyChanged")) {
+ dbus_message_iter_init(message, &iter);
+
+ if (state_online(&iter)) {
+ if (devices)
+ manager_get_services(devices);
+ else
+ g_main_loop_quit(main_loop);
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static gboolean timeout_triggered(gpointer user_data)
+{
+ exit_value = -ETIMEDOUT;
+ g_main_loop_quit(main_loop);
+ timeout = 0;
+
+ return FALSE;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *filter = "type='signal',interface='"
+ CONNMAN_MANAGER_INTERFACE "'";
+ int err = 0;
+ GError *g_err = NULL;
+ struct devices devices = { NULL, NULL };
+ DBusError dbus_err;
+ GOptionContext *context;
+
+ context = g_option_context_new(NULL);
+ g_option_context_add_main_entries(context, options, NULL);
+
+ if (!g_option_context_parse(context, &argc, &argv, &g_err)) {
+ if (g_err) {
+ fprintf(stderr, "%s\n", g_err->message);
+ g_error_free(g_err);
+ } else
+ fprintf(stderr, "An unknown error occurred\n");
+
+ return EOPNOTSUPP;
+ }
+
+ g_option_context_free(context);
+
+ if (option_interface) {
+ devices.interface = g_strsplit(option_interface, ",", -1);
+ g_free(option_interface);
+ }
+
+ if (option_ignore) {
+ devices.ignore = g_strsplit(option_ignore, ",", -1);
+ g_free(option_ignore);
+ }
+
+ if (option_version) {
+ fprintf(stdout, "%s\n", VERSION);
+ goto free;
+ }
+
+ dbus_error_init(&dbus_err);
+ connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &dbus_err);
+
+ if (dbus_error_is_set(&dbus_err)) {
+ fprintf(stderr, "Error: %s\n", dbus_err.message);
+
+ err = -ENOPROTOOPT;
+ goto fail;
+ }
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+
+ dbus_connection_add_filter(connection, manager_property_changed,
+ &devices, NULL);
+
+ dbus_bus_add_match(connection, filter, &dbus_err);
+
+ if (dbus_error_is_set(&dbus_err)) {
+ fprintf(stderr, "Error: %s\n", dbus_err.message);
+
+ err = -ENOPROTOOPT;
+ goto cleanup;
+ }
+
+ if (option_timeout)
+ timeout = g_timeout_add_seconds(option_timeout,
+ timeout_triggered, NULL);
+
+ manager_get_properties(&devices);
+
+ g_main_loop_run(main_loop);
+ err = exit_value;
+
+cleanup:
+ dbus_bus_remove_match(connection, filter, NULL);
+ dbus_connection_remove_filter(connection, manager_property_changed,
+ &devices);
+
+ dbus_connection_unref(connection);
+ g_main_loop_unref(main_loop);
+
+fail:
+ dbus_error_free(&dbus_err);
+free:
+ g_strfreev(devices.interface);
+ g_strfreev(devices.ignore);
+ if (timeout)
+ g_source_remove(timeout);
+
+ return -err;
+}
diff --git a/src/device.c b/src/device.c
index b5855cc2..3ec8f715 100755
--- a/src/device.c
+++ b/src/device.c
@@ -53,7 +53,6 @@ struct connman_device {
*/
bool powered;
bool scanning;
- bool disconnected;
char *name;
char *node;
char *address;
@@ -385,6 +384,9 @@ static void device_destruct(struct connman_device *device)
clear_pending_trigger(device);
+ g_hash_table_destroy(device->networks);
+ device->networks = NULL;
+
g_free(device->ident);
g_free(device->node);
g_free(device->name);
@@ -394,9 +396,6 @@ static void device_destruct(struct connman_device *device)
g_free(device->last_network);
- g_hash_table_destroy(device->networks);
- device->networks = NULL;
-
g_free(device);
}
@@ -568,7 +567,7 @@ int connman_device_set_powered(struct connman_device *device,
{
enum connman_service_type type;
- DBG("driver %p powered %d", device, powered);
+ DBG("device %p powered %d", device, powered);
if (device->powered == powered)
return -EALREADY;
@@ -588,7 +587,6 @@ int connman_device_set_powered(struct connman_device *device,
__connman_technology_enabled(type);
- connman_device_set_disconnected(device, false);
device->scanning = false;
if (device->driver && device->driver->scan)
@@ -623,8 +621,6 @@ int __connman_device_disconnect(struct connman_device *device)
DBG("device %p", device);
- connman_device_set_disconnected(device, true);
-
g_hash_table_iter_init(&iter, device->networks);
while (g_hash_table_iter_next(&iter, &key, &value)) {
@@ -751,37 +747,6 @@ int connman_device_set_scanning(struct connman_device *device,
}
/**
- * connman_device_set_disconnected:
- * @device: device structure
- * @disconnected: disconnected state
- *
- * Change disconnected state of device (only for device with networks)
- */
-int connman_device_set_disconnected(struct connman_device *device,
- bool disconnected)
-{
- DBG("device %p disconnected %d", device, disconnected);
-
- if (device->disconnected == disconnected)
- return -EALREADY;
-
- device->disconnected = disconnected;
-
- return 0;
-}
-
-/**
- * connman_device_get_disconnected:
- * @device: device structure
- *
- * Get device disconnected state
- */
-bool connman_device_get_disconnected(struct connman_device *device)
-{
- return device->disconnected;
-}
-
-/**
* connman_device_set_string:
* @device: device structure
* @key: unique identifier
@@ -1435,6 +1400,11 @@ nodevice:
}
list:
+ if (__connman_inet_isrootnfs_device(devname)) {
+ DBG("ignoring device %s (rootnfs)", devname);
+ return true;
+ }
+
blacklisted_interfaces =
connman_setting_get_string_list("NetworkInterfaceBlacklist");
if (!blacklisted_interfaces)
diff --git a/src/dhcp.c b/src/dhcp.c
index b6273625..c428c1d4 100755
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -26,6 +26,11 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <net/ethernet.h>
+
+#ifndef IPV6_MIN_MTU
+#define IPV6_MIN_MTU 1280
+#endif
#include <connman/ipconfig.h>
#include <include/setting.h>
@@ -54,10 +59,11 @@ struct connman_dhcp {
GDHCPClient *dhcp_client;
char *ipv4ll_debug_prefix;
char *dhcp_debug_prefix;
+
+ bool ipv4ll_running;
};
static GHashTable *ipconfig_table;
-static bool ipv4ll_running;
static void dhcp_free(struct connman_dhcp *dhcp)
{
@@ -89,7 +95,7 @@ static void ipv4ll_stop_client(struct connman_dhcp *dhcp)
g_dhcp_client_stop(dhcp->ipv4ll_client);
g_dhcp_client_unref(dhcp->ipv4ll_client);
dhcp->ipv4ll_client = NULL;
- ipv4ll_running = false;
+ dhcp->ipv4ll_running = false;
g_free(dhcp->ipv4ll_debug_prefix);
dhcp->ipv4ll_debug_prefix = NULL;
@@ -117,18 +123,22 @@ static bool apply_dhcp_invalidate_on_network(struct connman_dhcp *dhcp)
__connman_service_timeserver_remove(service,
dhcp->timeservers[i]);
}
+ g_strfreev(dhcp->timeservers);
+ dhcp->timeservers = NULL;
}
if (dhcp->nameservers) {
for (i = 0; dhcp->nameservers[i]; i++) {
#if defined TIZEN_EXT
__connman_service_nameserver_remove(service,
- dhcp->nameservers[i], false,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ dhcp->nameservers[i], false,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
#else
__connman_service_nameserver_remove(service,
- dhcp->nameservers[i], false);
+ dhcp->nameservers[i], false);
#endif
}
+ g_strfreev(dhcp->nameservers);
+ dhcp->nameservers = NULL;
}
return true;
@@ -246,7 +256,7 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp)
return err;
}
- ipv4ll_running = true;
+ dhcp->ipv4ll_running = true;
return 0;
}
@@ -270,16 +280,16 @@ static void no_lease_cb(GDHCPClient *dhcp_client, gpointer user_data)
struct connman_dhcp *dhcp = user_data;
int err;
- DBG("No lease available ipv4ll %d client %p", ipv4ll_running,
+ DBG("No lease available ipv4ll %d client %p", dhcp->ipv4ll_running,
dhcp->ipv4ll_client);
if (dhcp->timeout > 0)
g_source_remove(dhcp->timeout);
dhcp->timeout = g_timeout_add_seconds(RATE_LIMIT_INTERVAL,
- dhcp_retry_cb,
- dhcp);
- if (ipv4ll_running)
+ dhcp_retry_cb,
+ dhcp);
+ if (dhcp->ipv4ll_running)
return;
err = ipv4ll_start_client(dhcp);
@@ -287,7 +297,7 @@ static void no_lease_cb(GDHCPClient *dhcp_client, gpointer user_data)
DBG("Cannot start ipv4ll client (%d/%s)", err, strerror(-err));
/* Only notify upper layer if we have a problem */
- dhcp_invalidate(dhcp, !ipv4ll_running);
+ dhcp_invalidate(dhcp, !dhcp->ipv4ll_running);
}
static void lease_lost_cb(GDHCPClient *dhcp_client, gpointer user_data)
@@ -352,6 +362,20 @@ static bool apply_lease_available_on_network(GDHCPClient *dhcp_client,
return false;
}
+ option = g_dhcp_client_get_option(dhcp_client, G_DHCP_MTU);
+ if (option && option->data) {
+ int mtu, index, err;
+
+ mtu = atoi(option->data);
+
+ if (mtu >= IPV6_MIN_MTU && mtu <= ETH_DATA_LEN) {
+ index = __connman_ipconfig_get_index(dhcp->ipconfig);
+ err = connman_inet_set_mtu(index, mtu);
+
+ DBG("MTU %d index %d err %d", mtu, index, err);
+ }
+ }
+
option = g_dhcp_client_get_option(dhcp_client, 252);
if (option)
pac = g_strdup(option->data);
@@ -452,6 +476,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
{
struct connman_dhcp *dhcp = user_data;
GList *option = NULL;
+ enum connman_ipconfig_method old_method;
char *address, *netmask = NULL, *gateway = NULL;
const char *c_address, *c_gateway;
unsigned char prefixlen, c_prefixlen;
@@ -507,6 +532,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
} else if (prefixlen != c_prefixlen)
ip_change = true;
+ old_method = __connman_ipconfig_get_method(dhcp->ipconfig);
__connman_ipconfig_set_method(dhcp->ipconfig,
CONNMAN_IPCONFIG_METHOD_DHCP);
@@ -514,6 +540,20 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
__connman_ipconfig_set_dhcp_lease_duration(dhcp->ipconfig, dhcp_lease_duration);
#endif
+ /*
+ * Notify IPv4.Configuration's method moved back to DHCP.
+ *
+ * This is the case ConnMan initially set an address by using
+ * IPv4LL because DHCP failed but now we got an address from DHCP.
+ */
+ if (old_method == CONNMAN_IPCONFIG_METHOD_AUTO) {
+ struct connman_service *service =
+ connman_service_lookup_from_network(dhcp->network);
+
+ if (service)
+ __connman_service_notify_ipv4_configuration(service);
+ }
+
if (ip_change) {
__connman_ipconfig_set_local(dhcp->ipconfig, address);
__connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen);
@@ -535,8 +575,9 @@ done:
static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data)
{
struct connman_dhcp *dhcp = user_data;
- char *address, *netmask;
- unsigned char prefixlen;
+ enum connman_ipconfig_method old_method;
+ char *address, *netmask;
+ unsigned char prefixlen;
DBG("IPV4LL available");
@@ -545,8 +586,25 @@ static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data)
prefixlen = connman_ipaddress_calc_netmask_len(netmask);
+ old_method = __connman_ipconfig_get_method(dhcp->ipconfig);
__connman_ipconfig_set_method(dhcp->ipconfig,
- CONNMAN_IPCONFIG_METHOD_DHCP);
+ CONNMAN_IPCONFIG_METHOD_AUTO);
+
+ /*
+ * Notify IPv4.Configuration's method is AUTO now.
+ *
+ * This is the case DHCP failed thus ConnMan used IPv4LL to get an
+ * address. Set IPv4.Configuration method to AUTO allows user to
+ * ask for a DHCP address by setting the method again to DHCP.
+ */
+ if (old_method == CONNMAN_IPCONFIG_METHOD_DHCP) {
+ struct connman_service *service =
+ connman_service_lookup_from_network(dhcp->network);
+
+ if (service)
+ __connman_service_notify_ipv4_configuration(service);
+ }
+
__connman_ipconfig_set_local(dhcp->ipconfig, address);
__connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen);
__connman_ipconfig_set_gateway(dhcp->ipconfig, NULL);
@@ -562,6 +620,7 @@ static int dhcp_initialize(struct connman_dhcp *dhcp)
GDHCPClient *dhcp_client;
GDHCPClientError error;
int index;
+ const char *vendor_class_id;
DBG("dhcp %p", dhcp);
@@ -610,10 +669,16 @@ static int dhcp_initialize(struct connman_dhcp *dhcp)
g_dhcp_client_set_request(dhcp_client, G_DHCP_DOMAIN_NAME);
g_dhcp_client_set_request(dhcp_client, G_DHCP_NTP_SERVER);
g_dhcp_client_set_request(dhcp_client, 252);
+ g_dhcp_client_set_request(dhcp_client, G_DHCP_MTU);
}
- g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET);
g_dhcp_client_set_request(dhcp_client, G_DHCP_ROUTER);
+ g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET);
+
+ vendor_class_id = connman_option_get_string("VendorClassID");
+ if (vendor_class_id)
+ g_dhcp_client_set_send(dhcp_client, G_DHCP_VENDOR_CLASS_ID,
+ vendor_class_id);
g_dhcp_client_register_event(dhcp_client,
G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE,
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index adf88273..c624cb00 100755
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -105,20 +105,14 @@ static void clear_timer(struct connman_dhcpv6 *dhcp)
}
}
-static inline guint get_random(void)
+static guint compute_random(guint val)
{
- uint64_t val;
-
- __connman_util_get_random(&val);
+ uint64_t rand;
- /* Make sure the value is always positive so strip MSB */
- return ((uint32_t)val) >> 1;
-}
+ __connman_util_get_random(&rand);
-static guint compute_random(guint val)
-{
return val - val / 10 +
- (get_random() % (2 * 1000)) * val / 10 / 1000;
+ ((guint) rand % (2 * 1000)) * val / 10 / 1000;
}
/* Calculate a random delay, RFC 3315 chapter 14 */
@@ -253,6 +247,7 @@ static int set_duid(struct connman_service *service,
hex_duid = convert_to_hex(duid, duid_len);
if (!hex_duid) {
+ g_free(duid);
g_key_file_free(keyfile);
return -ENOMEM;
}
@@ -481,7 +476,6 @@ static int check_ipv6_addr_prefix(GSList *prefixes, char *address)
if (!slash)
continue;
- prefix = g_strndup(prefix, slash - prefix);
len = strtol(slash + 1, NULL, 10);
if (len < 3 || len > 128)
break;
@@ -492,6 +486,7 @@ static int check_ipv6_addr_prefix(GSList *prefixes, char *address)
left = plen % 8;
i = 16 - count;
+ prefix = g_strndup(prefix, slash - prefix);
inet_pton(AF_INET6, prefix, &addr_prefix);
inet_pton(AF_INET6, address, &addr);
diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index 55ba69a6..3fa7bf46 100755
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -46,6 +46,8 @@
#include <systemd/sd-daemon.h>
#endif
+#define debug(fmt...) do { } while (0)
+
#if __BYTE_ORDER == __LITTLE_ENDIAN
struct domain_hdr {
uint16_t id;
@@ -301,7 +303,7 @@ static struct server_data *find_server(int index,
{
GSList *list;
- DBG("index %d server %s proto %d", index, server, protocol);
+ debug("index %d server %s proto %d", index, server, protocol);
for (list = server_list; list; list = list->next) {
struct server_data *data = list->data;
@@ -352,14 +354,14 @@ static void refresh_dns_entry(struct cache_entry *entry, char *name)
}
if (!entry->ipv4) {
- DBG("Refresing A record for %s", name);
+ debug("Refreshing A record for %s", name);
g_resolv_lookup_hostname(ipv4_resolve, name,
dummy_resolve_func, NULL);
age = 4;
}
if (!entry->ipv6) {
- DBG("Refresing AAAA record for %s", name);
+ debug("Refreshing AAAA record for %s", name);
g_resolv_lookup_hostname(ipv6_resolve, name,
dummy_resolve_func, NULL);
age = 4;
@@ -374,7 +376,7 @@ static int dns_name_length(unsigned char *buf)
{
if ((buf[0] & NS_CMPRSFLGS) == NS_CMPRSFLGS) /* compressed name */
return 2;
- return strlen((char *)buf);
+ return strlen((char *)buf) + 1;
}
static void update_cached_ttl(unsigned char *buf, int len, int new_ttl)
@@ -471,7 +473,7 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
else
update_cached_ttl((unsigned char *)hdr, adj_len, ttl);
- DBG("sk %d id 0x%04x answers %d ptr %p length %d dns %d",
+ debug("sk %d id 0x%04x answers %d ptr %p length %d dns %d",
sk, hdr->id, answers, ptr, len, dns_len);
err = sendto(sk, ptr, len, MSG_NOSIGNAL, to, tolen);
@@ -483,7 +485,7 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
if (err != len || (dns_len != (len - 2) && protocol == IPPROTO_TCP) ||
(dns_len != len && protocol == IPPROTO_UDP))
- DBG("Packet length mismatch, sent %d wanted %d dns %d",
+ debug("Packet length mismatch, sent %d wanted %d dns %d",
err, len, dns_len);
}
@@ -494,7 +496,7 @@ static void send_response(int sk, unsigned char *buf, int len,
struct domain_hdr *hdr;
int err, offset = protocol_offset(protocol);
- DBG("sk %d", sk);
+ debug("sk %d", sk);
if (offset < 0)
return;
@@ -504,7 +506,7 @@ static void send_response(int sk, unsigned char *buf, int len,
hdr = (void *) (buf + offset);
- DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
+ debug("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
hdr->qr = 1;
hdr->rcode = ns_r_servfail;
@@ -556,7 +558,7 @@ static gboolean request_timeout(gpointer user_data)
if (!req)
return FALSE;
- DBG("id 0x%04x", req->srcid);
+ debug("id 0x%04x", req->srcid);
request_list = g_slist_remove(request_list, req);
@@ -598,7 +600,7 @@ static gboolean request_timeout(gpointer user_data)
* if we get a request timeout from server.
*/
if (req->protocol == IPPROTO_TCP) {
- DBG("client %d removed", req->client_sk);
+ debug("client %d removed", req->client_sk);
g_hash_table_remove(partial_tcp_req_table,
GINT_TO_POINTER(req->client_sk));
}
@@ -616,7 +618,7 @@ static int append_query(unsigned char *buf, unsigned int size,
unsigned char *ptr = buf;
int len;
- DBG("query %s domain %s", query, domain);
+ debug("query %s domain %s", query, domain);
while (query) {
const char *tmp;
@@ -686,7 +688,7 @@ static void cache_enforce_validity(struct cache_entry *entry)
if (!cache_check_is_valid(entry->ipv4, current_time)
&& entry->ipv4) {
- DBG("cache timeout \"%s\" type A", entry->key);
+ debug("cache timeout \"%s\" type A", entry->key);
g_free(entry->ipv4->data);
g_free(entry->ipv4);
entry->ipv4 = NULL;
@@ -695,7 +697,7 @@ static void cache_enforce_validity(struct cache_entry *entry)
if (!cache_check_is_valid(entry->ipv6, current_time)
&& entry->ipv6) {
- DBG("cache timeout \"%s\" type AAAA", entry->key);
+ debug("cache timeout \"%s\" type AAAA", entry->key);
g_free(entry->ipv6->data);
g_free(entry->ipv6);
entry->ipv6 = NULL;
@@ -720,7 +722,7 @@ static uint16_t cache_check_validity(char *question, uint16_t type,
switch (type) {
case 1: /* IPv4 */
if (!cache_check_is_valid(entry->ipv4, current_time)) {
- DBG("cache %s \"%s\" type A", entry->ipv4 ?
+ debug("cache %s \"%s\" type A", entry->ipv4 ?
"timeout" : "entry missing", question);
if (want_refresh)
@@ -739,7 +741,7 @@ static uint16_t cache_check_validity(char *question, uint16_t type,
case 28: /* IPv6 */
if (!cache_check_is_valid(entry->ipv6, current_time)) {
- DBG("cache %s \"%s\" type AAAA", entry->ipv6 ?
+ debug("cache %s \"%s\" type AAAA", entry->ipv6 ?
"timeout" : "entry missing", question);
if (want_refresh)
@@ -785,7 +787,7 @@ static gboolean try_remove_cache(gpointer user_data)
cache_timer = 0;
if (__sync_fetch_and_sub(&cache_refcount, 1) == 1) {
- DBG("No cache users, removing it.");
+ debug("No cache users, removing it.");
g_hash_table_destroy(cache);
cache = NULL;
@@ -1002,7 +1004,7 @@ static int parse_response(unsigned char *buf, int buflen,
if (buflen < 12)
return -EINVAL;
- DBG("qr %d qdcount %d", hdr->qr, qdcount);
+ debug("qr %d qdcount %d", hdr->qr, qdcount);
/* We currently only cache responses where question count is 1 */
if (hdr->qr != 1 || qdcount != 1)
@@ -1248,7 +1250,7 @@ static void cache_cleanup(void)
count = g_hash_table_foreach_remove(cache, cache_check_entry,
&data);
}
- DBG("removed %d in the first pass", count);
+ debug("removed %d in the first pass", count);
/*
* In the second pass, if the first pass turned up blank,
@@ -1312,7 +1314,7 @@ static gboolean cache_invalidate_entry(gpointer key, gpointer value,
*/
static void cache_invalidate(void)
{
- DBG("Invalidating the DNS cache %p", cache);
+ debug("Invalidating the DNS cache %p", cache);
if (!cache)
return;
@@ -1344,7 +1346,7 @@ static void cache_refresh_entry(struct cache_entry *entry)
*c = '.';
c += jump + 1;
}
- DBG("Refreshing %s\n", dns_name);
+ debug("Refreshing %s\n", dns_name);
/* then refresh the hostname */
refresh_dns_entry(entry, &dns_name[1]);
}
@@ -1380,7 +1382,7 @@ static int reply_query_type(unsigned char *msg, int len)
return 0;
/* now the query, which is a name and 2 16 bit words */
- l = dns_name_length(c) + 1;
+ l = dns_name_length(c);
c += l;
type = c[0] << 8 | c[1];
@@ -1421,7 +1423,7 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
if (offset < 0)
return 0;
- DBG("offset %d hdr %p msg %p rcode %d", offset, hdr, msg, hdr->rcode);
+ debug("offset %d hdr %p msg %p rcode %d", offset, hdr, msg, hdr->rcode);
/* Continue only if response code is 0 (=ok) */
if (hdr->rcode != ns_r_noerror)
@@ -1601,7 +1603,7 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
cache_size++;
}
- DBG("cache %d %squestion \"%s\" type %d ttl %d size %zd packet %u "
+ debug("cache %d %squestion \"%s\" type %d ttl %d size %zd packet %u "
"dns len %u",
cache_size, new_entry ? "new " : "old ",
question, type, ttl,
@@ -1627,7 +1629,7 @@ static int ns_resolv(struct server_data *server, struct request_data *req,
int ttl_left = 0;
struct cache_data *data;
- DBG("cache hit %s type %s", lookup, type == 1 ? "A" : "AAAA");
+ debug("cache hit %s type %s", lookup, type == 1 ? "A" : "AAAA");
if (type == 1)
data = entry->ipv4;
else
@@ -1689,7 +1691,7 @@ static int ns_resolv(struct server_data *server, struct request_data *req,
err = sendto(sk, request, req->request_len, MSG_NOSIGNAL,
server->server_addr, server->server_addr_len);
if (err < 0) {
- DBG("Cannot send message to server %s sock %d "
+ debug("Cannot send message to server %s sock %d "
"protocol %d (%s/%d)",
server->server, sk, server->protocol,
strerror(errno), errno);
@@ -1749,7 +1751,7 @@ static int ns_resolv(struct server_data *server, struct request_data *req,
alt[1] = req_len & 0xff;
}
- DBG("req %p dstid 0x%04x altid 0x%04x", req, req->dstid,
+ debug("req %p dstid 0x%04x altid 0x%04x", req, req->dstid,
req->altid);
err = send(sk, alt, req->request_len + domlen, MSG_NOSIGNAL);
@@ -1771,7 +1773,7 @@ static char *convert_label(char *start, char *end, char *ptr, char *uptr,
pos = dn_expand((u_char *)start, (u_char *)end, (u_char *)ptr,
name, NS_MAXLABEL);
if (pos < 0) {
- DBG("uncompress error [%d/%s]", errno, strerror(errno));
+ debug("uncompress error [%d/%s]", errno, strerror(errno));
goto out;
}
@@ -1781,7 +1783,7 @@ static char *convert_label(char *start, char *end, char *ptr, char *uptr,
*/
comp_pos = dn_comp(name, (u_char *)uptr, remaining_len, NULL, NULL);
if (comp_pos < 0) {
- DBG("compress error [%d/%s]", errno, strerror(errno));
+ debug("compress error [%d/%s]", errno, strerror(errno));
goto out;
}
@@ -1800,7 +1802,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
{
char *uptr = *uncompressed_ptr; /* position in result buffer */
- DBG("count %d ptr %p end %p uptr %p", field_count, ptr, end, uptr);
+ debug("count %d ptr %p end %p uptr %p", field_count, ptr, end, uptr);
while (field_count-- > 0 && ptr < end) {
int dlen; /* data field length */
@@ -1822,7 +1824,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
ulen = strlen(name);
strncpy(uptr, name, uncomp_len - (uptr - uncompressed));
- DBG("pos %d ulen %d left %d name %s", pos, ulen,
+ debug("pos %d ulen %d left %d name %s", pos, ulen,
(int)(uncomp_len - (uptr - uncompressed)), uptr);
uptr += ulen;
@@ -1866,7 +1868,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
dlen = uptr[-2] << 8 | uptr[-1];
if (ptr + dlen > end) {
- DBG("data len %d too long", dlen);
+ debug("data len %d too long", dlen);
goto out;
}
@@ -1977,13 +1979,13 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
hdr = (void *)(reply + offset);
dns_id = reply[offset] | reply[offset + 1] << 8;
- DBG("Received %d bytes (id 0x%04x)", reply_len, dns_id);
+ debug("Received %d bytes (id 0x%04x)", reply_len, dns_id);
req = find_request(dns_id);
if (!req)
return -EINVAL;
- DBG("req %p dstid 0x%04x altid 0x%04x rcode %d",
+ debug("req %p dstid 0x%04x altid 0x%04x rcode %d",
req, req->dstid, req->altid, hdr->rcode);
reply[offset] = req->srcid & 0xff;
@@ -2039,7 +2041,7 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
ptr[dns_type_pos + 3];
if (dns_type != ns_t_a && dns_type != ns_t_aaaa &&
dns_class != ns_c_in) {
- DBG("Pass msg dns type %d class %d",
+ debug("Pass msg dns type %d class %d",
dns_type, dns_class);
goto pass;
}
@@ -2098,21 +2100,21 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
(char *)reply + offset, eom,
ptr, uncompressed, NS_MAXDNAME,
&uptr);
- if (ptr == NULL)
+ if (!ptr)
goto out;
ptr = uncompress(ntohs(hdr->nscount),
(char *)reply + offset, eom,
ptr, uncompressed, NS_MAXDNAME,
&uptr);
- if (ptr == NULL)
+ if (!ptr)
goto out;
ptr = uncompress(ntohs(hdr->arcount),
(char *)reply + offset, eom,
ptr, uncompressed, NS_MAXDNAME,
&uptr);
- if (ptr == NULL)
+ if (!ptr)
goto out;
/*
@@ -2128,7 +2130,7 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
new_len = strip_domains(uncompressed, answers,
uptr - answers);
if (new_len < 0) {
- DBG("Corrupted packet");
+ debug("Corrupted packet");
return -EINVAL;
}
@@ -2193,10 +2195,10 @@ out:
}
if (err < 0)
- DBG("Cannot send msg, sk %d proto %d errno %d/%s", sk,
+ debug("Cannot send msg, sk %d proto %d errno %d/%s", sk,
protocol, errno, strerror(errno));
else
- DBG("proto %d sent %d bytes to %d", protocol, err, sk);
+ debug("proto %d sent %d bytes to %d", protocol, err, sk);
destroy_request_data(req);
@@ -2205,7 +2207,7 @@ out:
static void server_destroy_socket(struct server_data *data)
{
- DBG("index %d server %s proto %d", data->index,
+ debug("index %d server %s proto %d", data->index,
data->server, data->protocol);
if (data->watch > 0) {
@@ -2230,7 +2232,7 @@ static void server_destroy_socket(struct server_data *data)
static void destroy_server(struct server_data *server)
{
- DBG("index %d server %s sock %d", server->index, server->server,
+ debug("index %d server %s sock %d", server->index, server->server,
server->channel ?
g_io_channel_unix_get_fd(server->channel): -1);
@@ -2238,7 +2240,7 @@ static void destroy_server(struct server_data *server)
server_destroy_socket(server);
if (server->protocol == IPPROTO_UDP && server->enabled)
- DBG("Removing DNS server %s", server->server);
+ debug("Removing DNS server %s", server->server);
g_free(server->server);
g_list_free_full(server->domains, g_free);
@@ -2311,7 +2313,7 @@ static gboolean tcp_server_event(GIOChannel *channel, GIOCondition condition,
if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
GSList *list;
hangup:
- DBG("TCP server channel closed, sk %d", sk);
+ debug("TCP server channel closed, sk %d", sk);
/*
* Discard any partial response which is buffered; better
@@ -2320,9 +2322,11 @@ hangup:
g_free(server->incoming_reply);
server->incoming_reply = NULL;
- for (list = request_list; list; list = list->next) {
+ list = request_list;
+ while (list) {
struct request_data *req = list->data;
struct domain_hdr *hdr;
+ list = list->next;
if (req->protocol == IPPROTO_UDP)
continue;
@@ -2364,7 +2368,7 @@ hangup:
domains = domains->next) {
char *dom = domains->data;
- DBG("Adding domain %s to %s",
+ debug("Adding domain %s to %s",
dom, server->server);
server->domains = g_list_append(server->domains,
@@ -2389,7 +2393,7 @@ hangup:
continue;
}
- DBG("Sending req %s over TCP", (char *)req->name);
+ debug("Sending req %s over TCP", (char *)req->name);
status = ns_resolv(server, req,
req->request, req->name);
@@ -2448,7 +2452,7 @@ hangup:
reply_len = reply_len_buf[1] | reply_len_buf[0] << 8;
reply_len += 2;
- DBG("TCP reply %d bytes from %d", reply_len, sk);
+ debug("TCP reply %d bytes from %d", reply_len, sk);
reply = g_try_malloc(sizeof(*reply) + reply_len + 2);
if (!reply)
@@ -2495,7 +2499,7 @@ static gboolean tcp_idle_timeout(gpointer user_data)
{
struct server_data *server = user_data;
- DBG("");
+ debug("");
if (!server)
return FALSE;
@@ -2510,7 +2514,7 @@ static int server_create_socket(struct server_data *data)
int sk, err;
char *interface;
- DBG("index %d server %s proto %d", data->index,
+ debug("index %d server %s proto %d", data->index,
data->server, data->protocol);
sk = socket(data->server_addr->sa_family,
@@ -2524,7 +2528,7 @@ static int server_create_socket(struct server_data *data)
return -err;
}
- DBG("sk %d", sk);
+ debug("sk %d", sk);
interface = connman_inet_ifname(data->index);
if (interface) {
@@ -2584,6 +2588,25 @@ static int server_create_socket(struct server_data *data)
return 0;
}
+static void enable_fallback(bool enable)
+{
+ GSList *list;
+
+ for (list = server_list; list; list = list->next) {
+ struct server_data *data = list->data;
+
+ if (data->index != -1)
+ continue;
+
+ if (enable)
+ DBG("Enabling fallback DNS server %s", data->server);
+ else
+ DBG("Disabling fallback DNS server %s", data->server);
+
+ data->enabled = enable;
+ }
+}
+
#if defined TIZEN_EXT
static void destroy_server_sec(struct server_data *server)
@@ -2841,6 +2864,8 @@ static struct server_data *create_server(int index,
data->index)) {
data->enabled = true;
DBG("Adding DNS server %s", data->server);
+
+ enable_fallback(false);
}
server_list = g_slist_append(server_list, data);
@@ -2862,7 +2887,7 @@ static bool resolv(struct request_data *req,
continue;
}
- DBG("server %s enabled %d", data->server, data->enabled);
+ debug("server %s enabled %d", data->server, data->enabled);
if (!data->enabled)
continue;
@@ -2881,7 +2906,7 @@ static bool resolv(struct request_data *req,
return false;
}
-static void append_domain(int index, const char *domain)
+static void update_domain(int index, const char *domain, bool append)
{
GSList *list;
@@ -2912,13 +2937,27 @@ static void append_domain(int index, const char *domain)
}
}
- if (!dom_found) {
+ if (!dom_found && append) {
data->domains =
g_list_append(data->domains, g_strdup(domain));
+ } else if (dom_found && !append) {
+ data->domains =
+ g_list_remove(data->domains, dom);
+ g_free(dom);
}
}
}
+static void append_domain(int index, const char *domain)
+{
+ update_domain(index, domain, true);
+}
+
+static void remove_domain(int index, const char *domain)
+{
+ update_domain(index, domain, false);
+}
+
static void flush_requests(struct server_data *server)
{
GSList *list;
@@ -2988,12 +3027,22 @@ static void remove_server(int index, const char *domain,
const char *server, int protocol)
{
struct server_data *data;
+ GSList *list;
data = find_server(index, server, protocol);
if (!data)
return;
destroy_server(data);
+
+ for (list = server_list; list; list = list->next) {
+ struct server_data *data = list->data;
+
+ if (data->index != -1 && data->enabled == true)
+ return;
+ }
+
+ enable_fallback(true);
}
int __connman_dnsproxy_remove(int index, const char *domain,
@@ -3001,9 +3050,15 @@ int __connman_dnsproxy_remove(int index, const char *domain,
{
DBG("index %d server %s", index, server);
- if (!server)
+ if (!server && !domain)
return -EINVAL;
+ if (!server) {
+ remove_domain(index, domain);
+
+ return 0;
+ }
+
if (g_str_equal(server, "127.0.0.1"))
return -ENODEV;
@@ -3044,6 +3099,7 @@ static void dnsproxy_offline_mode(bool enabled)
static void dnsproxy_default_changed(struct connman_service *service)
{
+ bool server_enabled = false;
GSList *list;
int index;
@@ -3068,12 +3124,16 @@ static void dnsproxy_default_changed(struct connman_service *service)
if (data->index == index) {
DBG("Enabling DNS server %s", data->server);
data->enabled = true;
+ server_enabled = true;
} else {
DBG("Disabling DNS server %s", data->server);
data->enabled = false;
}
}
+ if (!server_enabled)
+ enable_fallback(true);
+
cache_refresh();
}
@@ -3098,7 +3158,7 @@ static int parse_request(unsigned char *buf, int len,
if (len < 12)
return -EINVAL;
- DBG("id 0x%04x qr %d opcode %d qdcount %d arcount %d",
+ debug("id 0x%04x qr %d opcode %d qdcount %d arcount %d",
hdr->id, hdr->qr, hdr->opcode,
qdcount, arcount);
@@ -3136,7 +3196,7 @@ static int parse_request(unsigned char *buf, int len,
edns0_bufsize = last_label[7] << 8 | last_label[8];
- DBG("EDNS0 buffer size %u", edns0_bufsize);
+ debug("EDNS0 buffer size %u", edns0_bufsize);
/* This is an evil hack until full TCP support has been
* implemented.
@@ -3152,7 +3212,7 @@ static int parse_request(unsigned char *buf, int len,
}
}
- DBG("query %s", name);
+ debug("query %s", name);
return 0;
}
@@ -3163,7 +3223,7 @@ static void client_reset(struct tcp_partial_client_data *client)
return;
if (client->channel) {
- DBG("client %d closing",
+ debug("client %d closing",
g_io_channel_unix_get_fd(client->channel));
g_io_channel_unref(client->channel);
@@ -3207,14 +3267,14 @@ static bool read_tcp_data(struct tcp_partial_client_data *client,
client_sk = g_io_channel_unix_get_fd(client->channel);
if (read_len == 0) {
- DBG("client %d closed, pending %d bytes",
+ debug("client %d closed, pending %d bytes",
client_sk, client->buf_end);
g_hash_table_remove(partial_tcp_req_table,
GINT_TO_POINTER(client_sk));
return false;
}
- DBG("client %d received %d bytes", client_sk, read_len);
+ debug("client %d received %d bytes", client_sk, read_len);
client->buf_end += read_len;
@@ -3223,24 +3283,24 @@ static bool read_tcp_data(struct tcp_partial_client_data *client,
msg_len = get_msg_len(client->buf);
if (msg_len > TCP_MAX_BUF_LEN) {
- DBG("client %d sent too much data %d", client_sk, msg_len);
+ debug("client %d sent too much data %d", client_sk, msg_len);
g_hash_table_remove(partial_tcp_req_table,
GINT_TO_POINTER(client_sk));
return false;
}
read_another:
- DBG("client %d msg len %d end %d past end %d", client_sk, msg_len,
+ debug("client %d msg len %d end %d past end %d", client_sk, msg_len,
client->buf_end, client->buf_end - (msg_len + 2));
if (client->buf_end < (msg_len + 2)) {
- DBG("client %d still missing %d bytes",
+ debug("client %d still missing %d bytes",
client_sk,
msg_len + 2 - client->buf_end);
return true;
}
- DBG("client %d all data %d received", client_sk, msg_len);
+ debug("client %d all data %d received", client_sk, msg_len);
err = parse_request(client->buf + 2, msg_len,
query, sizeof(query));
@@ -3281,7 +3341,7 @@ read_another:
int ttl_left = 0;
struct cache_data *data;
- DBG("cache hit %s type %s", query, qtype == 1 ? "A" : "AAAA");
+ debug("cache hit %s type %s", query, qtype == 1 ? "A" : "AAAA");
if (qtype == 1)
data = entry->ipv4;
else
@@ -3298,7 +3358,7 @@ read_another:
g_free(req);
goto out;
} else
- DBG("data missing, ignoring cache for this query");
+ debug("data missing, ignoring cache for this query");
}
for (list = server_list; list; list = list->next) {
@@ -3353,7 +3413,7 @@ read_another:
out:
if (client->buf_end > (msg_len + 2)) {
- DBG("client %d buf %p -> %p end %d len %d new %d",
+ debug("client %d buf %p -> %p end %d len %d new %d",
client_sk,
client->buf + msg_len + 2,
client->buf, client->buf_end,
@@ -3369,12 +3429,12 @@ out:
*/
msg_len = get_msg_len(client->buf);
if ((msg_len + 2) == client->buf_end) {
- DBG("client %d reading another %d bytes", client_sk,
+ debug("client %d reading another %d bytes", client_sk,
msg_len + 2);
goto read_another;
}
} else {
- DBG("client %d clearing reading buffer", client_sk);
+ debug("client %d clearing reading buffer", client_sk);
client->buf_end = 0;
memset(client->buf, 0, TCP_MAX_BUF_LEN);
@@ -3436,7 +3496,7 @@ static gboolean tcp_client_event(GIOChannel *channel, GIOCondition condition,
if (errno == EAGAIN || errno == EWOULDBLOCK)
return TRUE;
- DBG("client %d cannot read errno %d/%s", client_sk, -errno,
+ debug("client %d cannot read errno %d/%s", client_sk, -errno,
strerror(errno));
g_hash_table_remove(partial_tcp_req_table,
GINT_TO_POINTER(client_sk));
@@ -3453,7 +3513,7 @@ static gboolean client_timeout(gpointer user_data)
sock = g_io_channel_unix_get_fd(client->channel);
- DBG("client %d timeout pending %d bytes", sock, client->buf_end);
+ debug("client %d timeout pending %d bytes", sock, client->buf_end);
g_hash_table_remove(partial_tcp_req_table, GINT_TO_POINTER(sock));
@@ -3493,7 +3553,7 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
struct timeval tv;
fd_set readfds;
- DBG("condition 0x%02x channel %p ifdata %p family %d",
+ debug("condition 0x%02x channel %p ifdata %p family %d",
condition, channel, ifdata, family);
if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -3529,9 +3589,9 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
select(sk + 1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(sk, &readfds)) {
client_sk = accept(sk, client_addr, client_addr_len);
- DBG("client %d accepted", client_sk);
+ debug("client %d accepted", client_sk);
} else {
- DBG("No data to read from master %d, waiting.", sk);
+ debug("No data to read from master %d, waiting.", sk);
return true;
}
@@ -3565,9 +3625,9 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
client->ifdata = ifdata;
- DBG("client %d created %p", client_sk, client);
+ debug("client %d created %p", client_sk, client);
} else {
- DBG("client %d already exists %p", client_sk, client);
+ debug("client %d already exists %p", client_sk, client);
}
if (!client->buf) {
@@ -3591,11 +3651,11 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
len = recv(client_sk, client->buf, TCP_MAX_BUF_LEN, 0);
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
- DBG("client %d no data to read, waiting", client_sk);
+ debug("client %d no data to read, waiting", client_sk);
return true;
}
- DBG("client %d cannot read errno %d/%s", client_sk, -errno,
+ debug("client %d cannot read errno %d/%s", client_sk, -errno,
strerror(errno));
g_hash_table_remove(partial_tcp_req_table,
GINT_TO_POINTER(client_sk));
@@ -3603,14 +3663,14 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
}
if (len < 2) {
- DBG("client %d not enough data to read, waiting", client_sk);
+ debug("client %d not enough data to read, waiting", client_sk);
client->buf_end += len;
return true;
}
msg_len = get_msg_len(client->buf);
if (msg_len > TCP_MAX_BUF_LEN) {
- DBG("client %d invalid message length %u ignoring packet",
+ debug("client %d invalid message length %u ignoring packet",
client_sk, msg_len);
g_hash_table_remove(partial_tcp_req_table,
GINT_TO_POINTER(client_sk));
@@ -3626,7 +3686,7 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
#else
if (msg_len != (unsigned int)(len - 2)) {
#endif
- DBG("client %d sent %d bytes but expecting %u pending %d",
+ debug("client %d sent %d bytes but expecting %u pending %d",
client_sk, len, msg_len + 2, msg_len + 2 - len);
client->buf_end += len;
@@ -3696,7 +3756,7 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
if (len < 2)
return true;
- DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
+ debug("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
err = parse_request(buf, len, query, sizeof(query));
if (err < 0 || (g_slist_length(server_list) == 0)) {
@@ -3788,7 +3848,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
int is_socket_inet = 0;
#endif
- DBG("family %d protocol %d index %d", family, protocol, index);
+ debug("family %d protocol %d index %d", family, protocol, index);
switch (protocol) {
case IPPROTO_UDP:
@@ -4087,7 +4147,7 @@ static void destroy_listener(struct listener_data *ifdata)
for (list = request_list; list; list = list->next) {
struct request_data *req = list->data;
- DBG("Dropping request (id 0x%04x -> 0x%04x)",
+ debug("Dropping request (id 0x%04x -> 0x%04x)",
req->srcid, req->dstid);
destroy_request_data(req);
list->data = NULL;
diff --git a/src/firewall.c b/src/firewall-iptables.c
index 90c3d3c1..45943a82 100755..100644
--- a/src/firewall.c
+++ b/src/firewall-iptables.c
@@ -2,7 +2,7 @@
*
* Connection Manager
*
- * Copyright (C) 2013 BMW Car IT GmbH.
+ * Copyright (C) 2013,2015 BMW Car IT GmbH.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -46,6 +46,7 @@ struct connman_managed_table {
};
struct fw_rule {
+ bool enabled;
char *table;
char *chain;
char *rule_spec;
@@ -56,8 +57,8 @@ struct firewall_context {
};
static GSList *managed_tables;
-
-static bool firewall_is_up;
+static struct firewall_context *connmark_ctx;
+static unsigned int connmark_ref;
static int chain_to_index(const char *chain_name)
{
@@ -267,7 +268,55 @@ void __connman_firewall_destroy(struct firewall_context *ctx)
g_free(ctx);
}
-int __connman_firewall_add_rule(struct firewall_context *ctx,
+static int enable_rule(struct fw_rule *rule)
+{
+ int err;
+
+ if (rule->enabled)
+ return -EALREADY;
+
+ DBG("%s %s %s", rule->table, rule->chain, rule->rule_spec);
+
+ err = insert_managed_rule(rule->table, rule->chain, rule->rule_spec);
+ if (err < 0)
+ return err;
+
+ err = __connman_iptables_commit(rule->table);
+ if (err < 0)
+ return err;
+
+ rule->enabled = true;
+
+ return 0;
+}
+
+static int disable_rule(struct fw_rule *rule)
+{
+ int err;
+
+ if (!rule->enabled)
+ return -EALREADY;
+
+ err = delete_managed_rule(rule->table, rule->chain, rule->rule_spec);
+ if (err < 0) {
+ connman_error("Cannot remove previously installed "
+ "iptables rules: %s", strerror(-err));
+ return err;
+ }
+
+ err = __connman_iptables_commit(rule->table);
+ if (err < 0) {
+ connman_error("Cannot remove previously installed "
+ "iptables rules: %s", strerror(-err));
+ return err;
+ }
+
+ rule->enabled = false;
+
+ return 0;
+}
+
+static void firewall_add_rule(struct firewall_context *ctx,
const char *table,
const char *chain,
const char *rule_fmt, ...)
@@ -284,85 +333,208 @@ int __connman_firewall_add_rule(struct firewall_context *ctx,
rule = g_new0(struct fw_rule, 1);
+ rule->enabled = false;
rule->table = g_strdup(table);
rule->chain = g_strdup(chain);
rule->rule_spec = rule_spec;
ctx->rules = g_list_append(ctx->rules, rule);
-
- return 0;
}
-static int firewall_disable(GList *rules)
+static void firewall_remove_rules(struct firewall_context *ctx)
{
struct fw_rule *rule;
GList *list;
- int err;
- for (list = rules; list; list = g_list_previous(list)) {
+ for (list = g_list_last(ctx->rules); list;
+ list = g_list_previous(list)) {
rule = list->data;
- err = delete_managed_rule(rule->table,
- rule->chain, rule->rule_spec);
- if (err < 0) {
- connman_error("Cannot remove previously installed "
- "iptables rules: %s", strerror(-err));
- return err;
- }
+ ctx->rules = g_list_remove(ctx->rules, rule);
+ cleanup_fw_rule(rule);
+ }
+}
- err = __connman_iptables_commit(rule->table);
- if (err < 0) {
- connman_error("Cannot remove previously installed "
- "iptables rules: %s", strerror(-err));
- return err;
- }
+static int firewall_enable_rules(struct firewall_context *ctx)
+{
+ struct fw_rule *rule;
+ GList *list;
+ int err = -ENOENT;
+
+ for (list = g_list_first(ctx->rules); list; list = g_list_next(list)) {
+ rule = list->data;
+
+ err = enable_rule(rule);
+ if (err < 0)
+ break;
}
- return 0;
+ return err;
}
-int __connman_firewall_enable(struct firewall_context *ctx)
+static int firewall_disable_rules(struct firewall_context *ctx)
{
struct fw_rule *rule;
GList *list;
- int err;
+ int e;
+ int err = -ENOENT;
- for (list = g_list_first(ctx->rules); list;
- list = g_list_next(list)) {
+ for (list = g_list_last(ctx->rules); list;
+ list = g_list_previous(list)) {
rule = list->data;
- DBG("%s %s %s", rule->table, rule->chain, rule->rule_spec);
+ e = disable_rule(rule);
- err = insert_managed_rule(rule->table,
- rule->chain, rule->rule_spec);
- if (err < 0)
- goto err;
-
- err = __connman_iptables_commit(rule->table);
- if (err < 0)
- goto err;
+ /* Report last error back */
+ if (e == 0 && err == -ENOENT)
+ err = 0;
+ else if (e < 0)
+ err = e;
}
- firewall_is_up = true;
+ return err;
+}
+
+int __connman_firewall_enable_nat(struct firewall_context *ctx,
+ char *address, unsigned char prefixlen,
+ char *interface)
+{
+ char *cmd;
+ int err;
+ cmd = g_strdup_printf("-s %s/%d -o %s -j MASQUERADE",
+ address, prefixlen, interface);
+
+ firewall_add_rule(ctx, "nat", "POSTROUTING", cmd);
+ g_free(cmd);
+ err = firewall_enable_rules(ctx);
+ if (err)
+ firewall_remove_rules(ctx);
+ return err;
+}
+
+int __connman_firewall_disable_nat(struct firewall_context *ctx)
+{
+ int err;
+
+ err = firewall_disable_rules(ctx);
+ if (err < 0) {
+ DBG("could not disable NAT rule");
+ return err;
+ }
+
+ firewall_remove_rules(ctx);
return 0;
+}
-err:
- connman_warn("Failed to install iptables rules: %s", strerror(-err));
+int __connman_firewall_enable_snat(struct firewall_context *ctx,
+ int index, const char *ifname,
+ const char *addr)
+{
+ int err;
- firewall_disable(g_list_previous(list));
+ firewall_add_rule(ctx, "nat", "POSTROUTING",
+ "-o %s -j SNAT --to-source %s",
+ ifname, addr);
+ err = firewall_enable_rules(ctx);
+ if (err)
+ firewall_remove_rules(ctx);
return err;
}
-int __connman_firewall_disable(struct firewall_context *ctx)
+int __connman_firewall_disable_snat(struct firewall_context *ctx)
+{
+ int err;
+
+ err = firewall_disable_rules(ctx);
+ if (err < 0) {
+ DBG("could not disable SNAT rule");
+ return err;
+ }
+
+ firewall_remove_rules(ctx);
+ return 0;
+}
+
+static int firewall_enable_connmark(void)
{
- return firewall_disable(g_list_last(ctx->rules));
+ int err;
+
+ if (connmark_ref > 0) {
+ connmark_ref++;
+ return 0;
+ }
+
+ connmark_ctx = __connman_firewall_create();
+
+ firewall_add_rule(connmark_ctx, "mangle", "INPUT",
+ "-j CONNMARK --restore-mark");
+ firewall_add_rule(connmark_ctx, "mangle", "POSTROUTING",
+ "-j CONNMARK --save-mark");
+ err = firewall_enable_rules(connmark_ctx);
+ if (err) {
+ __connman_firewall_destroy(connmark_ctx);
+ connmark_ctx = NULL;
+ return err;
+ }
+ connmark_ref++;
+ return 0;
}
-bool __connman_firewall_is_up(void)
+static void firewall_disable_connmark(void)
{
- return firewall_is_up;
+ connmark_ref--;
+ if (connmark_ref > 0)
+ return;
+
+ firewall_disable_rules(connmark_ctx);
+ __connman_firewall_destroy(connmark_ctx);
+ connmark_ctx = NULL;
+}
+
+int __connman_firewall_enable_marking(struct firewall_context *ctx,
+ enum connman_session_id_type id_type,
+ char *id, const char *src_ip,
+ uint32_t mark)
+{
+ int err;
+
+ err = firewall_enable_connmark();
+ if (err)
+ return err;
+
+ switch (id_type) {
+ case CONNMAN_SESSION_ID_TYPE_UID:
+ firewall_add_rule(ctx, "mangle", "OUTPUT",
+ "-m owner --uid-owner %s -j MARK --set-mark %d",
+ id, mark);
+ break;
+ case CONNMAN_SESSION_ID_TYPE_GID:
+ firewall_add_rule(ctx, "mangle", "OUTPUT",
+ "-m owner --gid-owner %s -j MARK --set-mark %d",
+ id, mark);
+ break;
+ case CONNMAN_SESSION_ID_TYPE_UNKNOWN:
+ break;
+ case CONNMAN_SESSION_ID_TYPE_LSM:
+ default:
+ return -EINVAL;
+ }
+
+ if (src_ip) {
+ firewall_add_rule(ctx, "mangle", "OUTPUT",
+ "-s %s -j MARK --set-mark %d",
+ src_ip, mark);
+ }
+
+ return firewall_enable_rules(ctx);
+}
+
+int __connman_firewall_disable_marking(struct firewall_context *ctx)
+{
+ firewall_disable_connmark();
+ return firewall_disable_rules(ctx);
}
static void iterate_chains_cb(const char *chain_name, void *user_data)
@@ -432,12 +604,9 @@ static void flush_all_tables(void)
if (!g_file_test("/proc/net/ip_tables_names",
G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
- firewall_is_up = false;
return;
}
- firewall_is_up = true;
-
flush_table("filter");
flush_table("mangle");
flush_table("nat");
@@ -447,6 +616,7 @@ int __connman_firewall_init(void)
{
DBG("");
+ __connman_iptables_init();
flush_all_tables();
return 0;
@@ -457,4 +627,5 @@ void __connman_firewall_cleanup(void)
DBG("");
g_slist_free_full(managed_tables, cleanup_managed_table);
+ __connman_iptables_cleanup();
}
diff --git a/src/firewall-nftables.c b/src/firewall-nftables.c
new file mode 100644
index 00000000..1febce44
--- /dev/null
+++ b/src/firewall-nftables.c
@@ -0,0 +1,1133 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2016 BMW Car IT GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/*
+ * This file is based on the libnftnl examples:
+ * https://git.netfilter.org/libnftnl/tree/examples
+ * by Pablo Neira Ayuso. and inspiration from systemd nft implemention
+ * https://github.com/zonque/systemd/blob/rfc-nftnl/src/shared/firewall-util.c
+ * by Daniel Mack.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <alloca.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <libmnl/libmnl.h>
+#include <libnftnl/table.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+#include <glib.h>
+
+#include "connman.h"
+
+#define CONNMAN_TABLE "connman"
+#define CONNMAN_CHAIN_NAT_PRE "nat-prerouting"
+#define CONNMAN_CHAIN_NAT_POST "nat-postrouting"
+#define CONNMAN_CHAIN_ROUTE_OUTPUT "route-output"
+
+static bool debug_enabled = true;
+
+struct firewall_handle {
+ uint64_t handle;
+ const char *chain;
+};
+
+struct firewall_context {
+ struct firewall_handle rule;
+};
+
+struct nftables_info {
+ struct firewall_handle ct;
+};
+
+static struct nftables_info *nft_info;
+
+enum callback_return_type {
+ CALLBACK_RETURN_NONE = 0,
+ CALLBACK_RETURN_HANDLE,
+ CALLBACK_RETURN_BYTE_COUNTER,
+ _CALLBACK_RETURN_MAX,
+};
+
+struct callback_data {
+ enum callback_return_type type;
+ uint64_t value;
+ bool success;
+};
+
+static void debug_netlink_dump_rule(struct nftnl_rule *nlr)
+{
+ char buf[4096];
+
+ if (!debug_enabled)
+ return;
+
+ nftnl_rule_snprintf(buf, sizeof(buf), nlr, 0, 0);
+ fprintf(stdout, "%s\n", buf);
+}
+
+static void debug_mnl_dump_rule(const void *req, size_t req_size)
+{
+ if (!debug_enabled)
+ return;
+
+ mnl_nlmsg_fprintf(stdout, req, req_size, 0);
+ printf("\n");
+}
+
+static int rule_expr_cb(struct nftnl_expr *expr, void *data) {
+
+ struct callback_data *cb = data;
+ const char *name;
+
+ name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
+
+ if (strcmp(name, "counter")) {
+ cb->value = nftnl_expr_get_u64(expr, NFTNL_EXPR_CTR_BYTES);
+ cb->success = true;
+ }
+
+ return 0;
+}
+
+static int rule_cb(const struct nlmsghdr *nlh, int event,
+ struct callback_data *cb)
+{
+ struct nftnl_rule *rule;
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return MNL_CB_OK;
+
+ if (nftnl_rule_nlmsg_parse(nlh, rule) < 0)
+ goto out;
+
+ switch (cb->type) {
+ case CALLBACK_RETURN_HANDLE:
+ cb->value = nftnl_rule_get_u64(rule, NFTNL_RULE_HANDLE);
+ cb->success = true;
+ break;
+
+ case CALLBACK_RETURN_BYTE_COUNTER:
+ nftnl_expr_foreach(rule, rule_expr_cb, cb);
+ break;
+
+ default:
+ DBG("unhandled callback type %d\n", cb->type);
+ break;
+ }
+
+out:
+ nftnl_rule_free(rule);
+ return MNL_CB_STOP;
+}
+
+static int chain_cb(const struct nlmsghdr *nlh, int event,
+ struct callback_data *cb)
+{
+ struct nftnl_chain *chain;
+
+ chain = nftnl_chain_alloc();
+ if (!chain)
+ return MNL_CB_OK;
+
+ if (nftnl_chain_nlmsg_parse(nlh, chain) < 0)
+ goto out;
+
+ switch (cb->type) {
+ case CALLBACK_RETURN_HANDLE:
+ cb->value = nftnl_chain_get_u64(chain, NFTNL_CHAIN_HANDLE);
+ cb->success = true;
+ break;
+
+ default:
+ DBG("unhandled callback type %d\n", cb->type);
+ break;
+ }
+
+out:
+ nftnl_chain_free(chain);
+ return MNL_CB_OK;
+}
+
+static const char *event_to_str(enum nf_tables_msg_types type)
+{
+ const char *table[] = {
+ "NFT_MSG_NEWTABLE",
+ "NFT_MSG_GETTABLE",
+ "NFT_MSG_DELTABLE",
+ "NFT_MSG_NEWCHAIN",
+ "NFT_MSG_GETCHAIN",
+ "NFT_MSG_DELCHAIN",
+ "NFT_MSG_NEWRULE",
+ "NFT_MSG_GETRULE",
+ "NFT_MSG_DELRULE",
+ "NFT_MSG_NEWSET",
+ "NFT_MSG_GETSET",
+ "NFT_MSG_DELSET",
+ "NFT_MSG_NEWSETELEM",
+ "NFT_MSG_GETSETELEM",
+ "NFT_MSG_DELSETELEM",
+ "NFT_MSG_NEWGEN",
+ "NFT_MSG_GETGEN",
+ "NFT_MSG_TRACE"
+ };
+
+ if (type < sizeof(table)/sizeof(table[0]))
+ return table[type];
+
+ return "unknown";
+}
+
+static int events_cb(const struct nlmsghdr *nlh, void *data)
+{
+ int event = NFNL_MSG_TYPE(nlh->nlmsg_type);
+ struct callback_data *cb = data;
+ int err = MNL_CB_OK;
+
+ if (!cb || cb->type == CALLBACK_RETURN_NONE)
+ return err;
+
+ DBG("handle event %s", event_to_str(event));
+
+ switch(event) {
+ case NFT_MSG_NEWCHAIN:
+ err = chain_cb(nlh, event, cb);
+ break;
+
+ case NFT_MSG_NEWRULE:
+ err = rule_cb(nlh, event, cb);
+ break;
+ default:
+ DBG("unhandled event type %s", event_to_str(event));
+ break;
+ }
+
+ return err;
+}
+
+static int socket_open_and_bind(struct mnl_socket **n)
+{
+
+ struct mnl_socket *nl = NULL;
+ int err;
+
+ nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (!nl)
+ return -errno;
+
+ err = mnl_socket_bind(nl, 1 << (NFNLGRP_NFTABLES-1),
+ MNL_SOCKET_AUTOPID);
+ if (err < 0) {
+ err = errno;
+ mnl_socket_close(nl);
+ return -err;
+ }
+
+ *n = nl;
+ return 0;
+}
+
+static int send_and_dispatch(struct mnl_socket *nl, const void *req,
+ size_t req_size, enum callback_return_type callback_type,
+ uint64_t *callback_value)
+{
+ struct callback_data cb = {};
+ uint32_t portid;
+ int err;
+
+ debug_mnl_dump_rule(req, req_size);
+
+ err = mnl_socket_sendto(nl, req, req_size);
+ if (err < 0)
+ return -errno;
+
+ portid = mnl_socket_get_portid(nl);
+ cb.type = callback_type;
+
+ for (;;) {
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ err = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ if (err <= 0)
+ break;
+
+ err = mnl_cb_run(buf, err, 0, portid, events_cb, &cb);
+ if (err <= 0)
+ break;
+ }
+
+ if (err < 0)
+ return -errno;
+
+ if (callback_type == CALLBACK_RETURN_NONE)
+ return 0;
+
+ if (cb.success) {
+ if (callback_value)
+ *callback_value = cb.value;
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static void put_batch_headers(char *buf, uint16_t type, uint32_t seq)
+{
+
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfg;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = type;
+ nlh->nlmsg_flags = NLM_F_REQUEST;
+ nlh->nlmsg_seq = seq;
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = AF_INET;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = NFNL_SUBSYS_NFTABLES;
+}
+
+static int add_payload(struct nftnl_rule *rule, uint32_t base,
+ uint32_t dreg, uint32_t offset, uint32_t len)
+{
+ struct nftnl_expr *expr;
+
+ expr = nftnl_expr_alloc("payload");
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, dreg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len);
+
+ nftnl_rule_add_expr(rule, expr);
+
+ return 0;
+}
+
+static int add_bitwise(struct nftnl_rule *rule, int reg, const void *mask,
+ size_t len)
+{
+ struct nftnl_expr *expr;
+ uint8_t *xor;
+
+ expr = nftnl_expr_alloc("bitwise");
+ if (!expr)
+ return -ENOMEM;
+
+ xor = alloca(len);
+ memset(xor, 0, len);
+
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, reg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len);
+ nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len);
+ nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, xor, len);
+
+ nftnl_rule_add_expr(rule, expr);
+
+ return 0;
+}
+
+static int add_cmp(struct nftnl_rule *rule, uint32_t sreg, uint32_t op,
+ const void *data, uint32_t data_len)
+{
+ struct nftnl_expr *expr;
+
+ expr = nftnl_expr_alloc("cmp");
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op);
+ nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, data_len);
+
+ nftnl_rule_add_expr(rule, expr);
+
+ return 0;
+}
+
+static int table_cmd(struct mnl_socket *nl, struct nftnl_table *t,
+ uint16_t cmd, uint16_t family, uint16_t type)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct mnl_nlmsg_batch *batch;
+ struct nlmsghdr *nlh;
+ uint32_t seq = 0;
+ int err;
+
+ batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
+ nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
+ mnl_nlmsg_batch_next(batch);
+
+ nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+ cmd, family, type, seq++);
+ nftnl_table_nlmsg_build_payload(nlh, t);
+ nftnl_table_free(t);
+ mnl_nlmsg_batch_next(batch);
+
+ nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
+ mnl_nlmsg_batch_next(batch);
+
+ /* The current table commands do not support any callback returns. */
+ err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
+ mnl_nlmsg_batch_size(batch), 0, NULL);
+
+ mnl_nlmsg_batch_stop(batch);
+ return err;
+}
+
+static int chain_cmd(struct mnl_socket *nl, struct nftnl_chain *chain,
+ uint16_t cmd, int family, uint16_t type,
+ enum callback_return_type cb_type, uint64_t *cb_val)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct mnl_nlmsg_batch *batch;
+ struct nlmsghdr *nlh;
+ uint32_t seq = 0;
+ int err;
+
+ batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
+ nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
+ mnl_nlmsg_batch_next(batch);
+
+ nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+ cmd, family, type, seq++);
+ nftnl_chain_nlmsg_build_payload(nlh, chain);
+ nftnl_chain_free(chain);
+ mnl_nlmsg_batch_next(batch);
+
+ nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
+ mnl_nlmsg_batch_next(batch);
+
+ err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
+ mnl_nlmsg_batch_size(batch), cb_type, cb_val);
+
+ mnl_nlmsg_batch_stop(batch);
+ return err;
+}
+
+static int rule_cmd(struct mnl_socket *nl, struct nftnl_rule *rule,
+ uint16_t cmd, uint16_t family, uint16_t type,
+ enum callback_return_type callback_type,
+ uint64_t *callback_value)
+{
+
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct mnl_nlmsg_batch *batch;
+ struct nlmsghdr *nlh;
+ uint32_t seq = 0;
+ int err;
+
+ debug_netlink_dump_rule(rule);
+
+ batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
+ put_batch_headers(mnl_nlmsg_batch_current(batch),
+ NFNL_MSG_BATCH_BEGIN, seq++);
+ mnl_nlmsg_batch_next(batch);
+
+ nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+ cmd, family, type, seq++);
+ nftnl_rule_nlmsg_build_payload(nlh, rule);
+ mnl_nlmsg_batch_next(batch);
+
+ put_batch_headers(mnl_nlmsg_batch_current(batch),
+ NFNL_MSG_BATCH_END, seq++);
+ mnl_nlmsg_batch_next(batch);
+
+ err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
+ mnl_nlmsg_batch_size(batch),
+ callback_type, callback_value);
+ mnl_nlmsg_batch_stop(batch);
+
+ return err;
+}
+
+static int rule_delete(struct firewall_handle *handle)
+{
+ struct nftnl_rule *rule;
+ struct mnl_socket *nl;
+ int err;
+
+ DBG("");
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return -ENOMEM;
+
+ nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set(rule, NFTNL_RULE_CHAIN, handle->chain);
+ nftnl_rule_set_u64(rule, NFTNL_RULE_HANDLE, handle->handle);
+
+ err = socket_open_and_bind(&nl);
+ if (err < 0) {
+ nftnl_rule_free(rule);
+ return err;
+ }
+
+ err = rule_cmd(nl, rule, NFT_MSG_DELRULE, NFPROTO_IPV4,
+ NLM_F_ACK, 0, NULL);
+ nftnl_rule_free(rule);
+ mnl_socket_close(nl);
+
+ return err;
+}
+
+struct firewall_context *__connman_firewall_create(void)
+{
+ struct firewall_context *ctx;
+
+ DBG("");
+
+ ctx = g_new0(struct firewall_context, 1);
+
+ return ctx;
+}
+
+void __connman_firewall_destroy(struct firewall_context *ctx)
+{
+ DBG("");
+
+ g_free(ctx);
+}
+
+static int build_rule_nat(const char *address, unsigned char prefixlen,
+ const char *interface, struct nftnl_rule **res)
+{
+ struct nftnl_rule *rule;
+ struct in_addr ipv4_addr, ipv4_mask;
+ struct nftnl_expr *expr;
+ int err;
+
+ /*
+ * # nft --debug netlink add rule connman nat-postrouting \
+ * oifname eth0 ip saddr 10.10.0.0/24 masquerade
+ *
+ * ip connman nat-postrouting
+ * [ meta load oifname => reg 1 ]
+ * [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ * [ payload load 4b @ network header + 12 => reg 1 ]
+ * [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ * [ cmp eq reg 1 0x00000a0a ]
+ * [ masq ]
+ */
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return -ENOMEM;
+
+ nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
+
+ /* family ipv4 */
+ nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
+
+ /* oifname */
+ expr = nftnl_expr_alloc("meta");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIFNAME);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
+ nftnl_rule_add_expr(rule, expr);
+ err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, interface,
+ strlen(interface) + 1);
+ if (err < 0)
+ goto err;
+
+ /* source */
+ ipv4_mask.s_addr = htonl((0xffffffff << (32 - prefixlen)) & 0xffffffff);
+ ipv4_addr.s_addr = inet_addr(address);
+ ipv4_addr.s_addr &= ipv4_mask.s_addr;
+
+ err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
+ offsetof(struct iphdr, saddr), sizeof(struct in_addr));
+ if (err < 0)
+ goto err;
+ err = add_bitwise(rule, NFT_REG_1, &ipv4_mask.s_addr,
+ sizeof(struct in_addr));
+ if (err < 0)
+ goto err;
+ err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &ipv4_addr.s_addr,
+ sizeof(struct in_addr));
+ if (err < 0)
+ goto err;
+
+ /* masquerade */
+ expr = nftnl_expr_alloc("masq");
+ if (!expr)
+ goto err;
+ nftnl_rule_add_expr(rule, expr);
+
+ *res = rule;
+ return 0;
+
+err:
+ nftnl_rule_free(rule);
+ return -ENOMEM;
+}
+
+int __connman_firewall_enable_nat(struct firewall_context *ctx,
+ char *address, unsigned char prefixlen,
+ char *interface)
+{
+ struct mnl_socket *nl;
+ struct nftnl_rule *rule;
+ int err;
+
+ DBG("address %s/%d interface %s", address, (int)prefixlen, interface);
+
+ err = socket_open_and_bind(&nl);
+ if (err < 0)
+ return err;
+
+ err = build_rule_nat(address, prefixlen, interface, &rule);
+ if (err)
+ goto out;
+
+ ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
+ err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
+ NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
+ CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
+ nftnl_rule_free(rule);
+out:
+ mnl_socket_close(nl);
+ return err;
+}
+
+int __connman_firewall_disable_nat(struct firewall_context *ctx)
+{
+ return rule_delete(&ctx->rule);
+}
+
+static int build_rule_snat(int index, const char *address,
+ struct nftnl_rule **res)
+{
+ struct nftnl_rule *rule;
+ struct nftnl_expr *expr;
+ uint32_t snat;
+ int err;
+
+ /*
+ * # nft --debug netlink add rule connman nat-postrouting \
+ * oif eth0 snat 1.2.3.4
+ * ip connman nat-postrouting
+ * [ meta load oif => reg 1 ]
+ * [ cmp eq reg 1 0x0000000b ]
+ * [ immediate reg 1 0x04030201 ]
+ * [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ */
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return -ENOMEM;
+
+ nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
+
+ /* IOF */
+ expr = nftnl_expr_alloc("meta");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIF);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
+ nftnl_rule_add_expr(rule, expr);
+ err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &index, sizeof(index));
+ if (err < 0)
+ goto err;
+
+ /* snat */
+ expr = nftnl_expr_alloc("immediate");
+ if (!expr)
+ goto err;
+ snat = inet_addr(address);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
+ nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &snat, sizeof(snat));
+ nftnl_rule_add_expr(rule, expr);
+
+ expr = nftnl_expr_alloc("nat");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_TYPE, NFT_NAT_SNAT);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_FAMILY, NFPROTO_IPV4);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1);
+ nftnl_rule_add_expr(rule, expr);
+
+ *res = rule;
+ return 0;
+
+err:
+ nftnl_rule_free(rule);
+ return -ENOMEM;
+}
+
+int __connman_firewall_enable_snat(struct firewall_context *ctx,
+ int index, const char *ifname, const char *addr)
+{
+ struct nftnl_rule *rule;
+ struct mnl_socket *nl;
+ int err;
+
+ DBG("");
+
+ err = socket_open_and_bind(&nl);
+ if (err < 0)
+ return err;
+
+ err = build_rule_snat(index, addr, &rule);
+ if (err)
+ goto out;
+
+ ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
+ err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
+ NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
+ CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
+ nftnl_rule_free(rule);
+out:
+ mnl_socket_close(nl);
+ return err;
+}
+
+int __connman_firewall_disable_snat(struct firewall_context *ctx)
+{
+ DBG("");
+
+ return rule_delete(&ctx->rule);
+}
+
+static int build_rule_marking(uid_t uid, uint32_t mark, struct nftnl_rule **res)
+{
+ struct nftnl_rule *rule;
+ struct nftnl_expr *expr;
+ int err;
+
+ /*
+ * http://wiki.nftables.org/wiki-nftables/index.php/Setting_packet_metainformation
+ * http://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation
+ *
+ * # nft --debug netlink add rule connman route-output \
+ * meta skuid wagi mark set 1234
+ *
+ * ip connman route-output
+ * [ meta load skuid => reg 1 ]
+ * [ cmp eq reg 1 0x000003e8 ]
+ * [ immediate reg 1 0x000004d2 ]
+ * [ meta set mark with reg 1 ]
+ */
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return -ENOMEM;
+
+ nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
+
+ expr = nftnl_expr_alloc("meta");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_SKUID);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
+ nftnl_rule_add_expr(rule, expr);
+ err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &uid, sizeof(uid));
+ if (err < 0)
+ goto err;
+
+ expr = nftnl_expr_alloc("immediate");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
+ nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark));
+ nftnl_rule_add_expr(rule, expr);
+
+ expr = nftnl_expr_alloc("meta");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1);
+ nftnl_rule_add_expr(rule, expr);
+
+ *res = rule;
+ return 0;
+
+err:
+ return -ENOMEM;
+}
+
+static int build_rule_src_ip(const char *src_ip, uint32_t mark, struct nftnl_rule **res)
+{
+ struct nftnl_rule *rule;
+ struct nftnl_expr *expr;
+ int err;
+ in_addr_t s_addr;
+
+ /*
+ * # nft --debug netlink add rule connman route-output \
+ * ip saddr 192.168.10.31 mark set 1234
+ *
+ * ip connman route-output
+ * [ payload load 4b @ network header + 12 => reg 1 ]
+ * [ cmp eq reg 1 0x1f0aa8c0 ]
+ * [ immediate reg 1 0x000004d2 ]
+ * [ meta set mark with reg 1 ]
+ */
+
+ rule = nftnl_rule_alloc();
+ if (!rule)
+ return -ENOMEM;
+
+ nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+ nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
+
+ /* family ipv4 */
+ nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
+
+ /* source IP */
+ err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
+ offsetof(struct iphdr, saddr), sizeof(struct in_addr));
+ if (err < 0)
+ goto err;
+
+ s_addr = inet_addr(src_ip);
+ err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &s_addr, sizeof(s_addr));
+ if (err < 0)
+ goto err;
+
+ expr = nftnl_expr_alloc("immediate");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
+ nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark));
+ nftnl_rule_add_expr(rule, expr);
+
+ expr = nftnl_expr_alloc("meta");
+ if (!expr)
+ goto err;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1);
+ nftnl_rule_add_expr(rule, expr);
+
+ *res = rule;
+ return 0;
+
+err:
+ return -ENOMEM;
+}
+
+int __connman_firewall_enable_marking(struct firewall_context *ctx,
+ enum connman_session_id_type id_type,
+ char *id, const char *src_ip,
+ uint32_t mark)
+{
+ struct nftnl_rule *rule;
+ struct mnl_socket *nl;
+ struct passwd *pw;
+ uid_t uid;
+ int err;
+
+ DBG("");
+
+ if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
+ pw = getpwnam(id);
+ if (!pw)
+ return -EINVAL;
+ uid = pw->pw_uid;
+ }
+ else if (!src_ip)
+ return -ENOTSUP;
+
+ err = socket_open_and_bind(&nl);
+ if (err < 0)
+ return err;
+
+ if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
+ err = build_rule_marking(uid, mark, &rule);
+ if (err < 0)
+ goto out;
+
+ ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
+ err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
+ NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
+ CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
+
+ nftnl_rule_free(rule);
+ }
+
+ if (src_ip) {
+ err = build_rule_src_ip(src_ip, mark, &rule);
+ if (err < 0)
+ goto out;
+
+ ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
+ err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
+ NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
+ CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
+
+ nftnl_rule_free(rule);
+ }
+out:
+ mnl_socket_close(nl);
+ return err;
+}
+
+int __connman_firewall_disable_marking(struct firewall_context *ctx)
+{
+ int err;
+
+ DBG("");
+
+ err = rule_delete(&ctx->rule);
+ return err;
+}
+
+static struct nftnl_table *build_table(const char *name, uint16_t family)
+{
+ struct nftnl_table *table;
+
+ table = nftnl_table_alloc();
+ if (!table)
+ return NULL;
+
+ nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
+ nftnl_table_set_str(table, NFTNL_TABLE_NAME, name);
+
+ return table;
+}
+
+
+static struct nftnl_chain *build_chain(const char *name, const char *table,
+ const char *type, int hooknum, int prio)
+{
+ struct nftnl_chain *chain;
+
+ chain = nftnl_chain_alloc();
+ if (!chain)
+ return NULL;
+
+ nftnl_chain_set(chain, NFTNL_CHAIN_TABLE, table);
+ nftnl_chain_set(chain, NFTNL_CHAIN_NAME, name);
+
+ if (type)
+ nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type);
+
+ if (hooknum >= 0)
+ nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, hooknum);
+
+ if (prio >= 0)
+ nftnl_chain_set_u32(chain, NFTNL_CHAIN_PRIO, prio);
+
+ return chain;
+}
+
+static int create_table_and_chains(struct nftables_info *nft_info)
+{
+ struct mnl_socket *nl;
+ struct nftnl_table *table;
+ struct nftnl_chain *chain;
+ int err;
+
+
+ DBG("");
+
+ err = socket_open_and_bind(&nl);
+ if (err < 0)
+ return err;
+
+ /*
+ * Add table
+ * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
+ */
+
+ /*
+ * # nft add table connman
+ */
+ table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
+ if (!table) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = table_cmd(nl, table, NFT_MSG_NEWTABLE, NFPROTO_IPV4,
+ NLM_F_CREATE|NLM_F_ACK);
+ if (err < 0)
+ goto out;
+
+ /*
+ * Add basic chains
+ * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
+ */
+
+ /*
+ * # nft add chain connman nat-prerouting \
+ * { type nat hook prerouting priortiy 0 ; }
+ */
+ chain = build_chain(CONNMAN_CHAIN_NAT_PRE, CONNMAN_TABLE,
+ "nat", NF_INET_PRE_ROUTING, 0);
+ if (!chain) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
+ NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
+ CALLBACK_RETURN_NONE, NULL);
+ if (err < 0)
+ goto out;
+
+ /*
+ * # nft add chain connman nat-postrouting \
+ * { type nat hook postrouting priortiy 0 ; }
+ */
+ chain = build_chain(CONNMAN_CHAIN_NAT_POST, CONNMAN_TABLE,
+ "nat", NF_INET_POST_ROUTING, 0);
+ if (!chain) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
+ NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
+ CALLBACK_RETURN_NONE, NULL);
+ if (err < 0)
+ goto out;
+
+ /*
+ * # nft add chain connman route-output \
+ * { type route hook output priority 0 ; }
+ */
+ chain = build_chain(CONNMAN_CHAIN_ROUTE_OUTPUT, CONNMAN_TABLE,
+ "route", NF_INET_LOCAL_OUT, 0);
+ if (!chain) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
+ NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
+ CALLBACK_RETURN_NONE, NULL);
+ if (err < 0)
+ goto out;
+
+out:
+ if (err)
+ connman_warn("Failed to create basic chains: %s",
+ strerror(-err));
+ mnl_socket_close(nl);
+ return err;
+}
+
+static int cleanup_table_and_chains(void)
+{
+ struct nftnl_table *table;
+ struct mnl_socket *nl;
+ int err;
+
+ DBG("");
+
+ err = socket_open_and_bind(&nl);
+ if (err < 0)
+ return -ENOMEM;
+
+ /*
+ * Cleanup everythying in one go. There is little point in
+ * step-by-step removal of rules and chains if you can get it
+ * as simple as this.
+ */
+ /*
+ * # nft delete table connman
+ */
+ table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
+ err = table_cmd(nl, table, NFT_MSG_DELTABLE, NFPROTO_IPV4, NLM_F_ACK);
+
+ mnl_socket_close(nl);
+ return err;
+}
+
+int __connman_firewall_init(void)
+{
+ int err;
+
+ DBG("");
+
+ if (getenv("CONNMAN_NFTABLES_DEBUG"))
+ debug_enabled = true;
+
+ /*
+ * EAFNOSUPPORT is return whenever the nf_tables_ipv4 hasn't been
+ * loaded yet. ENOENT is return in case the table is missing.
+ */
+ err = cleanup_table_and_chains();
+ if (err < 0 && (err != EAFNOSUPPORT && err != -ENOENT)) {
+ connman_warn("initializing nftable failed with '%s' %d. Check if kernel module nf_tables_ipv4 is missing\n",
+ strerror(-err), err);
+ return err;
+ }
+
+ nft_info = g_new0(struct nftables_info, 1);
+ err = create_table_and_chains(nft_info);
+ if (err) {
+ g_free(nft_info);
+ nft_info = NULL;
+ }
+
+ return err;
+}
+
+void __connman_firewall_cleanup(void)
+{
+ int err;
+
+ DBG("");
+
+ err = cleanup_table_and_chains();
+ if (err < 0)
+ connman_warn("cleanup table and chains failed with '%s' %d\n",
+ strerror(-err), err);
+
+ g_free(nft_info);
+ nft_info = NULL;
+}
diff --git a/src/inet.c b/src/inet.c
index 02d96042..008f3de7 100755
--- a/src/inet.c
+++ b/src/inet.c
@@ -1307,13 +1307,12 @@ static gboolean rs_timeout_cb(gpointer user_data)
return FALSE;
}
-static int icmpv6_recv(int fd, gpointer user_data)
+static int icmpv6_recv(int fd, struct xs_cb_data *data)
{
struct msghdr mhdr;
struct iovec iov;
unsigned char chdr[CMSG_BUF_LEN];
unsigned char buf[1540];
- struct xs_cb_data *data = user_data;
struct nd_router_advert *hdr;
struct sockaddr_in6 saddr;
ssize_t len;
@@ -1335,7 +1334,6 @@ static int icmpv6_recv(int fd, gpointer user_data)
len = recvmsg(fd, &mhdr, 0);
if (len < 0) {
cb(NULL, 0, data->user_data);
- xs_cleanup(data);
return -errno;
}
@@ -1377,7 +1375,6 @@ static int icmpv6_recv(int fd, gpointer user_data)
return 0;
cb(hdr, len, data->user_data);
- xs_cleanup(data);
return len;
}
@@ -1385,18 +1382,21 @@ static int icmpv6_recv(int fd, gpointer user_data)
static gboolean icmpv6_event(GIOChannel *chan, GIOCondition cond, gpointer data)
{
int fd, ret;
+ struct xs_cb_data *xs_data = data;
DBG("");
if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
- return FALSE;
+ goto cleanup;
fd = g_io_channel_unix_get_fd(chan);
- ret = icmpv6_recv(fd, data);
+ ret = icmpv6_recv(fd, xs_data);
if (ret == 0)
return TRUE;
- return FALSE;
+cleanup:
+ xs_cleanup(xs_data);
+ return TRUE;
}
/* Adapted from RFC 1071 "C" Implementation Example */
@@ -1759,13 +1759,12 @@ void __connman_inet_ipv6_stop_recv_rs(void *context)
xs_cleanup(context);
}
-static int icmpv6_rs_recv(int fd, gpointer user_data)
+static int icmpv6_rs_recv(int fd, struct xs_cb_data *data)
{
struct msghdr mhdr;
struct iovec iov;
unsigned char chdr[CMSG_BUF_LEN];
unsigned char buf[1540];
- struct xs_cb_data *data = user_data;
struct nd_router_solicit *hdr;
struct sockaddr_in6 saddr;
ssize_t len;
@@ -1804,17 +1803,20 @@ static gboolean icmpv6_rs_event(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
int fd, ret;
+ struct xs_cb_data *xs_data = data;
DBG("");
if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
- return FALSE;
+ goto cleanup;
fd = g_io_channel_unix_get_fd(chan);
- ret = icmpv6_rs_recv(fd, data);
+ ret = icmpv6_rs_recv(fd, xs_data);
if (ret == 0)
return TRUE;
+cleanup:
+ xs_data->watch_id = 0;
return FALSE;
}
@@ -1889,13 +1891,12 @@ static gboolean ns_timeout_cb(gpointer user_data)
return FALSE;
}
-static int icmpv6_nd_recv(int fd, gpointer user_data)
+static int icmpv6_nd_recv(int fd, struct xs_cb_data *data)
{
struct msghdr mhdr;
struct iovec iov;
unsigned char chdr[CMSG_BUF_LEN];
unsigned char buf[1540];
- struct xs_cb_data *data = user_data;
struct nd_neighbor_advert *hdr;
struct sockaddr_in6 saddr;
ssize_t len;
@@ -1917,7 +1918,6 @@ static int icmpv6_nd_recv(int fd, gpointer user_data)
len = recvmsg(fd, &mhdr, 0);
if (len < 0) {
cb(NULL, 0, &data->addr.sin6_addr, data->user_data);
- xs_cleanup(data);
return -errno;
}
@@ -1936,7 +1936,6 @@ static int icmpv6_nd_recv(int fd, gpointer user_data)
return 0;
cb(hdr, len, &data->addr.sin6_addr, data->user_data);
- xs_cleanup(data);
return len;
}
@@ -1945,18 +1944,21 @@ static gboolean icmpv6_nd_event(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
int fd, ret;
+ struct xs_cb_data *xs_data = data;
DBG("");
if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
- return FALSE;
+ goto cleanup;
fd = g_io_channel_unix_get_fd(chan);
- ret = icmpv6_nd_recv(fd, data);
+ ret = icmpv6_nd_recv(fd, xs_data);
if (ret == 0)
return TRUE;
- return FALSE;
+cleanup:
+ xs_cleanup(xs_data);
+ return TRUE;
}
int __connman_inet_ipv6_do_dad(int index, int timeout_ms,
@@ -2280,9 +2282,8 @@ static gboolean inet_rtnl_timeout_cb(gpointer user_data)
return FALSE;
}
-static int inet_rtnl_recv(GIOChannel *chan, gpointer user_data)
+static int inet_rtnl_recv(GIOChannel *chan, struct inet_rtnl_cb_data *rtnl_data)
{
- struct inet_rtnl_cb_data *rtnl_data = user_data;
struct __connman_inet_rtnl_handle *rth = rtnl_data->rtnl;
struct nlmsghdr *h = NULL;
struct sockaddr_nl nladdr;
@@ -2364,17 +2365,20 @@ static gboolean inet_rtnl_event(GIOChannel *chan, GIOCondition cond,
gpointer user_data)
{
int ret;
+ struct inet_rtnl_cb_data *rtnl_data = user_data;
DBG("");
if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
- return FALSE;
+ goto cleanup;
- ret = inet_rtnl_recv(chan, user_data);
- if (ret != 0)
+ ret = inet_rtnl_recv(chan, rtnl_data);
+ if (ret == 0)
return TRUE;
- return FALSE;
+cleanup:
+ inet_rtnl_cleanup(rtnl_data);
+ return TRUE;
}
int __connman_inet_rtnl_talk(struct __connman_inet_rtnl_handle *rtnl,
@@ -2383,13 +2387,12 @@ int __connman_inet_rtnl_talk(struct __connman_inet_rtnl_handle *rtnl,
{
struct sockaddr_nl nladdr;
struct inet_rtnl_cb_data *data;
- unsigned seq;
int err;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
- n->nlmsg_seq = seq = ++rtnl->seq;
+ n->nlmsg_seq = ++rtnl->seq;
if (callback) {
data = g_try_malloc0(sizeof(struct inet_rtnl_cb_data));
@@ -2403,7 +2406,6 @@ int __connman_inet_rtnl_talk(struct __connman_inet_rtnl_handle *rtnl,
inet_rtnl_timeout_cb, data);
data->channel = g_io_channel_unix_new(rtnl->fd);
- g_io_channel_set_close_on_unref(data->channel, TRUE);
g_io_channel_set_encoding(data->channel, NULL, NULL);
g_io_channel_set_buffered(data->channel, FALSE);
@@ -2747,7 +2749,7 @@ char **__connman_inet_get_running_interfaces(void)
result = g_try_realloc(result, (count + 1) * sizeof(char *));
if (!result) {
g_free(prev_result);
- goto error;
+ return NULL;
}
}
@@ -3058,3 +3060,302 @@ out:
close(sk);
return ret;
}
+
+static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
+ struct in_addr *addr)
+{
+ char *s, *nfsargs;
+ size_t len;
+ char addrstr[INET_ADDRSTRLEN];
+ struct in_addr taddr;
+ GError *error = NULL;
+ char *cmdline = NULL;
+ char *pnp = NULL;
+ char **args = NULL;
+ char **pnpent = NULL;
+ char **pp = NULL;
+ int err = -1;
+
+ if (!cmdline_file)
+ cmdline_file = "/proc/cmdline";
+ if (!pnp_file)
+ pnp_file = "/proc/net/pnp";
+ if (!addr)
+ addr = &taddr;
+ addr->s_addr = INADDR_NONE;
+
+ if (!g_file_get_contents(cmdline_file, &cmdline, NULL, &error)) {
+ connman_error("%s: Cannot read %s %s\n", __func__,
+ cmdline_file, error->message);
+ goto out;
+ }
+
+ if (g_file_test(pnp_file, G_FILE_TEST_EXISTS)) {
+ if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+ connman_error("%s: Cannot read %s %s\n", __func__,
+ pnp_file, error->message);
+ goto out;
+ }
+ } else {
+ connman_error("%s: File %s doesn't exist\n", __func__, pnp_file);
+ goto out;
+ }
+
+ len = strlen(cmdline);
+ if (len <= 1) {
+ /* too short */
+ goto out;
+ }
+ /* remove newline */
+ if (cmdline[len - 1] == '\n')
+ cmdline[--len] = '\0';
+
+ /* split in arguments (seperated by space) */
+ args = g_strsplit(cmdline, " ", 0);
+ if (!args) {
+ connman_error("%s: Cannot split cmdline \"%s\"\n", __func__,
+ cmdline);
+ goto out;
+ }
+
+ /* split in entries (by newlines) */
+ pnpent = g_strsplit(pnp, "\n", 0);
+ if (!pnpent) {
+ connman_error("%s: Cannot split pnp at file \"%s\"\n", __func__,
+ pnp_file);
+ goto out;
+ }
+
+ /* first find root argument */
+ for (pp = args; *pp; pp++) {
+ if (!strcmp(*pp, "root=/dev/nfs"))
+ break;
+ }
+ /* no rootnfs found */
+ if (!*pp)
+ goto out;
+
+ /* locate nfsroot argument */
+ for (pp = args; *pp; pp++) {
+ if (!strncmp(*pp, "nfsroot=", strlen("nfsroot=")))
+ break;
+ }
+ /* no nfsroot argument found */
+ if (!*pp)
+ goto out;
+
+ /* determine if nfsroot server is provided */
+ nfsargs = strchr(*pp, '=');
+ if (!nfsargs)
+ goto out;
+ nfsargs++;
+
+ /* find whether serverip is present */
+ s = strchr(nfsargs, ':');
+ if (s) {
+ len = s - nfsargs;
+ s = nfsargs;
+ } else {
+ /* no serverip, use bootserver */
+ for (pp = pnpent; *pp; pp++) {
+ if (!strncmp(*pp, "bootserver ", strlen("bootserver ")))
+ break;
+ }
+ /* no bootserver found */
+ if (!*pp)
+ goto out;
+ s = *pp + strlen("bootserver ");
+ len = strlen(s);
+ }
+
+ /* copy to addr string buffer */
+ if (len >= sizeof(addrstr)) {
+ connman_error("%s: Bad server\n", __func__);
+ goto out;
+ }
+ memcpy(addrstr, s, len);
+ addrstr[len] = '\0';
+
+ err = inet_pton(AF_INET, addrstr, addr);
+ if (err <= 0) {
+ connman_error("%s: Cannot convert to numeric addr \"%s\"\n",
+ __func__, addrstr);
+ err = -1;
+ goto out;
+ }
+
+ /* all done */
+ err = 0;
+out:
+ g_strfreev(pnpent);
+ g_strfreev(args);
+ if (error)
+ g_error_free(error);
+ g_free(pnp);
+ g_free(cmdline);
+
+ return err;
+}
+
+/* get interface out of which peer is reachable (IPv4 only) */
+static int get_peer_iface(struct in_addr *addr, char *ifname)
+{
+ struct ifaddrs *ifaddr, *ifa;
+ struct sockaddr_in saddr, *ifsaddr;
+ socklen_t socklen;
+ int s;
+ int err = -1;
+
+ /* Obtain address(es) matching host/port */
+ err = getifaddrs(&ifaddr);
+ if (err < 0) {
+ connman_error("%s: getifaddrs() failed %d (%s)\n",
+ __func__, errno, strerror(errno));
+ return -1;
+ }
+
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0) {
+ connman_error("%s: socket() failed %d (%s)\n",
+ __func__, errno, strerror(errno));
+ return -1;
+ }
+
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = 0; /* any port */
+ saddr.sin_addr = *addr;
+
+ /* no need to bind, connect will select iface */
+ err = connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
+ if (err < 0) {
+ connman_error("%s: connect() failed: %d (%s)\n",
+ __func__, errno, strerror(errno));
+ goto out;
+ }
+
+ socklen = sizeof(saddr);
+ err = getsockname(s, (struct sockaddr *)&saddr, &socklen);
+ if (err < 0) {
+ connman_error("%s: getsockname() failed: %d (%s)\n",
+ __func__, errno, strerror(errno));
+ goto out;
+ }
+
+ err = -1;
+ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+
+ /* only IPv4 address */
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+
+ ifsaddr = (struct sockaddr_in *)ifa->ifa_addr;
+
+ /* match address? */
+ if (ifsaddr->sin_addr.s_addr == saddr.sin_addr.s_addr)
+ break;
+ }
+
+ if (ifa) {
+ err = 0;
+ if (ifname)
+ strcpy(ifname, ifa->ifa_name);
+ }
+
+out:
+ close(s);
+
+ freeifaddrs(ifaddr);
+
+ return err;
+}
+
+bool __connman_inet_isrootnfs_device(const char *devname)
+{
+ struct in_addr addr;
+ char ifname[IFNAMSIZ];
+
+ return get_nfs_server_ip(NULL, NULL, &addr) == 0 &&
+ get_peer_iface(&addr, ifname) == 0 &&
+ strcmp(devname, ifname) == 0;
+}
+
+char **__connman_inet_get_pnp_nameservers(const char *pnp_file)
+{
+ char **pp;
+ char *s;
+ int pass, count;
+ GError *error = NULL;
+ char *pnp = NULL;
+ char **pnpent = NULL;
+ char **nameservers = NULL;
+
+ if (!pnp_file)
+ pnp_file = "/proc/net/pnp";
+
+ if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
+ connman_error("%s: Cannot read %s %s\n", __func__,
+ pnp_file, error->message);
+ goto out;
+ }
+
+ /* split in entries (by newlines) */
+ pnpent = g_strsplit(pnp, "\n", 0);
+ if (!pnpent) {
+ connman_error("%s: Cannot split pnp \"%s\"\n", __func__,
+ pnp_file);
+ goto out;
+ }
+
+ /*
+ * Perform two passes to retreive a char ** array of
+ * nameservers that are not 0.0.0.0
+ *
+ * The first pass counts them, the second fills in the
+ * array.
+ */
+ count = 0;
+ nameservers = NULL;
+ for (pass = 1; pass <= 2; pass++) {
+
+ /* at the start of the second pass allocate */
+ if (pass == 2)
+ nameservers = g_new(char *, count + 1);
+
+ count = 0;
+ for (pp = pnpent; *pp; pp++) {
+ /* match 'nameserver ' at the start of each line */
+ if (strncmp(*pp, "nameserver ", strlen("nameserver ")))
+ continue;
+
+ /* compare it against 0.0.0.0 */
+ s = *pp + strlen("nameserver ");
+ if (!strcmp(s, "0.0.0.0"))
+ continue;
+
+ /* on second pass fill in array */
+ if (pass == 2)
+ nameservers[count] = g_strdup(s);
+ count++;
+ }
+
+ /* no nameservers? */
+ if (count == 0)
+ goto out;
+
+ /* and terminate char ** array with NULL */
+ if (pass == 2)
+ nameservers[count] = NULL;
+
+ }
+
+out:
+ g_strfreev(pnpent);
+ g_free(pnp);
+ if (error)
+ g_error_free(error);
+
+ return nameservers;
+}
diff --git a/src/ipconfig.c b/src/ipconfig.c
index ff1909d3..d94b8734 100755
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -48,7 +48,6 @@ struct connman_ipconfig {
const struct connman_ipconfig_ops *ops;
void *ops_data;
- bool enabled;
enum connman_ipconfig_method method;
struct connman_ipaddress *address;
struct connman_ipaddress *system;
@@ -413,40 +412,6 @@ static void free_ipdevice(gpointer data)
g_free(ipdevice);
}
-static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
-{
- DBG("ipconfig ipv4 %p ipv6 %p", ipdevice->config_ipv4,
- ipdevice->config_ipv6);
-#if defined TIZEN_EXT
- if (ipdevice->config_ipv6 != NULL &&
- ipdevice->config_ipv6->enabled == TRUE)
- return;
-
- char *ifname = connman_inet_ifname(ipdevice->index);
-
- if (__connman_device_isfiltered(ifname) == FALSE) {
- ipdevice->ipv6_enabled = get_ipv6_state(ifname);
- set_ipv6_state(ifname, FALSE);
- }
- g_free(ifname);
-#endif
-}
-
-static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
-{
- DBG("ipconfig ipv4 %p ipv6 %p", ipdevice->config_ipv4,
- ipdevice->config_ipv6);
-
- if (ipdevice->config_ipv4)
- connman_inet_clear_address(ipdevice->index,
- ipdevice->config_ipv4->address);
-
- if (ipdevice->config_ipv6)
- connman_inet_clear_ipv6_address(ipdevice->index,
- ipdevice->config_ipv6->address->local,
- ipdevice->config_ipv6->address->prefixlen);
-}
-
static void update_stats(struct connman_ipdevice *ipdevice,
const char *ifname, struct rtnl_link_stats *stats)
{
@@ -606,11 +571,6 @@ update:
g_list_free(ipconfig_copy);
- if (lower_up)
- __connman_ipconfig_lower_up(ipdevice);
- if (lower_down)
- __connman_ipconfig_lower_down(ipdevice);
-
out:
g_free(ifname);
}
@@ -651,8 +611,6 @@ void __connman_ipconfig_dellink(int index, struct rtnl_link_stats *stats)
g_free(ifname);
- __connman_ipconfig_lower_down(ipdevice);
-
g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
}
@@ -1178,8 +1136,6 @@ static struct connman_ipconfig *create_ipv6config(int index)
struct connman_ipconfig *ipv6config;
struct connman_ipdevice *ipdevice;
- DBG("index %d", index);
-
ipv6config = g_try_new0(struct connman_ipconfig, 1);
if (!ipv6config)
return NULL;
@@ -1187,7 +1143,6 @@ static struct connman_ipconfig *create_ipv6config(int index)
ipv6config->refcount = 1;
ipv6config->index = index;
- ipv6config->enabled = false;
ipv6config->type = CONNMAN_IPCONFIG_TYPE_IPV6;
if (!is_ipv6_supported)
@@ -1210,7 +1165,7 @@ static struct connman_ipconfig *create_ipv6config(int index)
ipv6config->system = connman_ipaddress_alloc(AF_INET6);
- DBG("ipconfig %p method %s", ipv6config,
+ DBG("ipconfig %p index %d method %s", ipv6config, index,
__connman_ipconfig_method2string(ipv6config->method));
return ipv6config;
@@ -1231,8 +1186,6 @@ struct connman_ipconfig *__connman_ipconfig_create(int index,
if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
return create_ipv6config(index);
- DBG("index %d", index);
-
ipconfig = g_try_new0(struct connman_ipconfig, 1);
if (!ipconfig)
return NULL;
@@ -1240,7 +1193,6 @@ struct connman_ipconfig *__connman_ipconfig_create(int index,
ipconfig->refcount = 1;
ipconfig->index = index;
- ipconfig->enabled = false;
ipconfig->type = CONNMAN_IPCONFIG_TYPE_IPV4;
ipconfig->address = connman_ipaddress_alloc(AF_INET);
@@ -1251,7 +1203,7 @@ struct connman_ipconfig *__connman_ipconfig_create(int index,
ipconfig->system = connman_ipaddress_alloc(AF_INET);
- DBG("ipconfig %p", ipconfig);
+ DBG("ipconfig %p index %d", ipconfig, index);
return ipconfig;
}
@@ -1384,8 +1336,6 @@ enum connman_ipconfig_method __connman_ipconfig_get_method(
int __connman_ipconfig_address_add(struct connman_ipconfig *ipconfig)
{
- DBG("");
-
switch (ipconfig->method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
@@ -1409,13 +1359,9 @@ int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig)
{
int err;
- DBG("");
-
if (!ipconfig)
return 0;
- DBG("method %d", ipconfig->method);
-
switch (ipconfig->method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
@@ -1437,8 +1383,6 @@ int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig)
{
int err;
- DBG("");
-
if (!ipconfig)
return 0;
@@ -1478,8 +1422,6 @@ int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig,
{
struct connman_ipdevice *ipdevice;
- DBG("ipconfig %p", ipconfig);
-
if (!ipconfig || ipconfig->index < 0)
return -ENODEV;
@@ -1498,8 +1440,6 @@ const char *__connman_ipconfig_get_proxy_autoconfig(struct connman_ipconfig *ipc
{
struct connman_ipdevice *ipdevice;
- DBG("ipconfig %p", ipconfig);
-
if (!ipconfig || ipconfig->index < 0)
return NULL;
@@ -1652,8 +1592,6 @@ int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
} else
return -EINVAL;
- ipconfig->enabled = true;
-
if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
ipdevice->config_ipv4) {
ipconfig_list = g_list_remove(ipconfig_list,
@@ -1728,8 +1666,6 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
if (!ipdevice->config_ipv4 && !ipdevice->config_ipv6)
return -EINVAL;
- ipconfig->enabled = false;
-
if (ipdevice->config_ipv4 == ipconfig) {
ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
@@ -1843,8 +1779,6 @@ int __connman_ipconfig_ipv6_set_privacy(struct connman_ipconfig *ipconfig,
if (!ipconfig)
return -EINVAL;
- DBG("ipconfig %p privacy %s", ipconfig, value);
-
privacy = string2privacy(value);
ipconfig->ipv6_privacy_config = privacy;
@@ -1859,9 +1793,6 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
{
struct connman_ipaddress *append_addr = NULL;
const char *str;
-#if defined TIZEN_EXT
- DBG("");
-#endif
if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
return;
@@ -1875,13 +1806,13 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
switch (ipconfig->method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
- case CONNMAN_IPCONFIG_METHOD_AUTO:
return;
case CONNMAN_IPCONFIG_METHOD_FIXED:
append_addr = ipconfig->address;
break;
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
case CONNMAN_IPCONFIG_METHOD_DHCP:
append_addr = ipconfig->system;
@@ -1936,9 +1867,6 @@ void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig,
{
struct connman_ipaddress *append_addr = NULL;
const char *str, *privacy;
-#if defined TIZEN_EXT
- DBG("");
-#endif
if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
return;
@@ -2000,9 +1928,6 @@ void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig,
DBusMessageIter *iter)
{
const char *str, *privacy;
-#if !defined TIZEN_EXT
- DBG("");
-#endif
str = __connman_ipconfig_method2string(ipconfig->method);
if (!str)
@@ -2045,9 +1970,6 @@ void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig,
DBusMessageIter *iter)
{
const char *str;
-#if !defined TIZEN_EXT
- DBG("");
-#endif
str = __connman_ipconfig_method2string(ipconfig->method);
if (!str)
@@ -2099,8 +2021,6 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
DBusMessageIter dict;
int type = -1;
- DBG("ipconfig %p", ipconfig);
-
if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
return -EINVAL;
@@ -2375,6 +2295,20 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
g_free(key);
break;
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+
+ if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
+ break;
+
+ /*
+ * If the last used method for IPv4 was AUTO then we
+ * try first DHCP. We will try also to use the last
+ * used DHCP address, if exits.
+ */
+ __connman_ipconfig_set_method(ipconfig,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
+ /* fall through */
+
case CONNMAN_IPCONFIG_METHOD_DHCP:
key = g_strdup_printf("%sDHCP.LastAddress", prefix);
@@ -2386,9 +2320,6 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
g_free(key);
break;
-
- case CONNMAN_IPCONFIG_METHOD_AUTO:
- break;
}
return 0;
@@ -2488,6 +2419,8 @@ int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
if (ipconfig->address->gateway)
g_key_file_set_string(keyfile, identifier,
key, ipconfig->address->gateway);
+ else
+ g_key_file_remove_key(keyfile, identifier, key, NULL);
g_free(key);
return 0;
diff --git a/src/ippool.c b/src/ippool.c
index bb8568d9..cea1dccd 100755
--- a/src/ippool.c
+++ b/src/ippool.c
@@ -58,7 +58,6 @@ struct connman_ippool {
};
GSList *allocated_blocks;
-GHashTable *pool_hash;
static uint32_t last_block;
static uint32_t block_16_bits;
@@ -90,7 +89,18 @@ void __connman_ippool_unref_debug(struct connman_ippool *pool,
if (__sync_fetch_and_sub(&pool->refcount, 1) != 1)
return;
- g_hash_table_remove(pool_hash, pool);
+ if (pool->info) {
+ allocated_blocks = g_slist_remove(allocated_blocks, pool->info);
+ g_free(pool->info);
+ }
+
+ g_free(pool->gateway);
+ g_free(pool->broadcast);
+ g_free(pool->start_ip);
+ g_free(pool->end_ip);
+ g_free(pool->subnet_mask);
+
+ g_free(pool);
}
static char *get_ip(uint32_t ip)
@@ -181,10 +191,10 @@ static uint32_t get_free_block(unsigned int size)
* To only thing we have to make sure is that we terminated if
* there is no block left.
*/
- if (last_block == 0)
- block = block_16_bits;
+ if (last_block)
+ block = last_block;
else
- block = next_block(last_block);
+ block = block_16_bits;
do {
collision = false;
@@ -393,7 +403,6 @@ struct connman_ippool *__connman_ippool_create(int index,
pool->end_ip = get_ip(block + start + range);
allocated_blocks = g_slist_prepend(allocated_blocks, info);
- g_hash_table_insert(pool_hash, pool, pool);
return pool;
}
@@ -423,24 +432,6 @@ const char *__connman_ippool_get_subnet_mask(struct connman_ippool *pool)
return pool->subnet_mask;
}
-static void pool_free(gpointer data)
-{
- struct connman_ippool *pool = data;
-
- if (pool->info) {
- allocated_blocks = g_slist_remove(allocated_blocks, pool->info);
- g_free(pool->info);
- }
-
- g_free(pool->gateway);
- g_free(pool->broadcast);
- g_free(pool->start_ip);
- g_free(pool->end_ip);
- g_free(pool->subnet_mask);
-
- g_free(pool);
-}
-
int __connman_ippool_init(void)
{
DBG("");
@@ -450,9 +441,6 @@ int __connman_ippool_init(void)
block_24_bits = ntohl(inet_addr("10.0.0.0"));
subnet_mask_24 = ntohl(inet_addr("255.255.255.0"));
- pool_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
- pool_free);
-
return 0;
}
@@ -460,9 +448,6 @@ void __connman_ippool_cleanup(void)
{
DBG("");
- g_hash_table_destroy(pool_hash);
- pool_hash = NULL;
-
g_slist_free_full(allocated_blocks, g_free);
last_block = 0;
allocated_blocks = NULL;
diff --git a/src/iptables.c b/src/iptables.c
index a5774ada..aaddf9d6 100755
--- a/src/iptables.c
+++ b/src/iptables.c
@@ -31,6 +31,7 @@
#include <sys/errno.h>
#include <sys/socket.h>
#include <xtables.h>
+#include <inttypes.h>
#include <linux/netfilter_ipv4/ip_tables.h>
@@ -154,6 +155,7 @@ struct error_target {
struct connman_iptables_entry {
int offset;
int builtin;
+ int counter_idx;
struct ipt_entry *entry;
};
@@ -251,8 +253,9 @@ static int print_entry(struct ipt_entry *entry, int builtin, unsigned int hook,
{
iterate_entries_cb_t cb = user_data;
- DBG("entry %p hook %d offset %d size %d", entry, hook,
- offset, entry->next_offset);
+ DBG("entry %p hook %u offset %u size %u packets %"PRIu64" bytes %"PRIu64,
+ entry, hook, offset, (unsigned int) entry->next_offset,
+ (uint64_t) entry->counters.pcnt, (uint64_t) entry->counters.bcnt);
return cb(entry, builtin, hook, size, offset, NULL);
}
@@ -460,7 +463,7 @@ static void update_targets_reference(struct connman_iptables *table,
static int iptables_add_entry(struct connman_iptables *table,
struct ipt_entry *entry, GList *before,
- int builtin)
+ int builtin, int counter_idx)
{
struct connman_iptables_entry *e, *entry_before;
@@ -473,6 +476,7 @@ static int iptables_add_entry(struct connman_iptables *table,
e->entry = entry;
e->builtin = builtin;
+ e->counter_idx = counter_idx;
table->entries = g_list_insert_before(table->entries, before, e);
table->num_entries++;
@@ -620,7 +624,7 @@ static int iptables_add_chain(struct connman_iptables *table,
error->t.u.user.target_size = ALIGN(sizeof(struct error_target));
g_stpcpy(error->error, name);
- if (iptables_add_entry(table, entry_head, last, -1) < 0)
+ if (iptables_add_entry(table, entry_head, last, -1, -1) < 0)
goto err_head;
/* tail entry */
@@ -638,7 +642,7 @@ static int iptables_add_chain(struct connman_iptables *table,
ALIGN(sizeof(struct ipt_standard_target));
standard->verdict = XT_RETURN;
- if (iptables_add_entry(table, entry_return, last, -1) < 0)
+ if (iptables_add_entry(table, entry_return, last, -1, -1) < 0)
goto err;
return 0;
@@ -826,7 +830,7 @@ static int iptables_append_rule(struct connman_iptables *table,
if (!new_entry)
return -EINVAL;
- ret = iptables_add_entry(table, new_entry, chain_tail->prev, builtin);
+ ret = iptables_add_entry(table, new_entry, chain_tail->prev, builtin, -1);
if (ret < 0)
g_free(new_entry);
@@ -857,7 +861,7 @@ static int iptables_insert_rule(struct connman_iptables *table,
if (builtin == -1)
chain_head = chain_head->next;
- ret = iptables_add_entry(table, new_entry, chain_head, builtin);
+ ret = iptables_add_entry(table, new_entry, chain_head, builtin, -1);
if (ret < 0)
g_free(new_entry);
@@ -1128,6 +1132,8 @@ static int iptables_change_policy(struct connman_iptables *table,
target = ipt_get_target(entry->entry);
t = (struct xt_standard_target *)target;
+ if (t->verdict != verdict)
+ entry->counter_idx = -1;
t->verdict = verdict;
return 0;
@@ -1405,6 +1411,19 @@ static int iptables_replace(struct connman_iptables *table,
return 0;
}
+static int iptables_add_counters(struct connman_iptables *table,
+ struct xt_counters_info *c)
+{
+ int err;
+
+ err = setsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_SET_ADD_COUNTERS, c,
+ sizeof(*c) + sizeof(struct xt_counters) * c->num_counters);
+ if (err < 0)
+ return -errno;
+
+ return 0;
+}
+
static int add_entry(struct ipt_entry *entry, int builtin, unsigned int hook,
size_t size, unsigned offset, void *user_data)
{
@@ -1417,7 +1436,8 @@ static int add_entry(struct ipt_entry *entry, int builtin, unsigned int hook,
memcpy(new_entry, entry, entry->next_offset);
- return iptables_add_entry(table, new_entry, NULL, builtin);
+ return iptables_add_entry(table, new_entry, NULL, builtin,
+ table->num_entries);
}
static void table_cleanup(struct connman_iptables *table)
@@ -1748,6 +1768,7 @@ struct parse_context {
struct xtables_target *xt_t;
GList *xt_m;
struct xtables_rule_match *xt_rm;
+ int proto;
};
static int prepare_getopt_args(const char *str, struct parse_context *ctx)
@@ -1787,6 +1808,14 @@ static int parse_xt_modules(int c, bool invert,
{
struct xtables_match *m;
struct xtables_rule_match *rm;
+ struct ipt_entry fw;
+
+ memset(&fw, 0, sizeof(fw));
+
+ /* The SNAT parser wants to know the protocol. */
+ if (ctx->proto == 0)
+ ctx->proto = IPPROTO_IP;
+ fw.ip.proto = ctx->proto;
for (rm = ctx->xt_rm; rm; rm = rm->next) {
if (rm->completed != 0)
@@ -1802,7 +1831,7 @@ static int parse_xt_modules(int c, bool invert,
+ XT_OPTION_OFFSET_SCALE)
continue;
- xtables_option_mpcall(c, ctx->argv, invert, m, NULL);
+ xtables_option_mpcall(c, ctx->argv, invert, m, &fw);
}
if (!ctx->xt_t)
@@ -1816,7 +1845,7 @@ static int parse_xt_modules(int c, bool invert,
+ XT_OPTION_OFFSET_SCALE)
return 0;
- xtables_option_tpcall(c, ctx->argv, invert, ctx->xt_t, NULL);
+ xtables_option_tpcall(c, ctx->argv, invert, ctx->xt_t, &fw);
return 0;
}
@@ -1991,6 +2020,9 @@ static int parse_rule_spec(struct connman_iptables *table,
ctx->xt_m = g_list_append(ctx->xt_m, xt_m);
break;
+ case 'p':
+ ctx->proto = xtables_parse_protocol(optarg);
+ break;
case 'j':
/* Target */
ctx->xt_t = prepare_target(table, optarg);
@@ -2306,6 +2338,10 @@ int __connman_iptables_commit(const char *table_name)
struct connman_iptables *table;
struct ipt_replace *repl;
int err;
+ struct xt_counters_info *counters;
+ struct connman_iptables_entry *e;
+ GList *list;
+ unsigned int cnt;
DBG("%s", table_name);
@@ -2314,25 +2350,44 @@ int __connman_iptables_commit(const char *table_name)
return -EINVAL;
repl = iptables_blob(table);
-#if defined TIZEN_EXT
if(!repl)
return -ENOMEM;
-#endif
if (debug_enabled)
dump_ipt_replace(repl);
err = iptables_replace(table, repl);
- g_free(repl->counters);
- g_free(repl);
+ if (err < 0)
+ goto out_free;
+
+ counters = g_try_malloc0(sizeof(*counters) +
+ sizeof(struct xt_counters) * table->num_entries);
+ if (!counters) {
+ err = -ENOMEM;
+ goto out_hash_remove;
+ }
+ g_stpcpy(counters->name, table->info->name);
+ counters->num_counters = table->num_entries;
+ for (list = table->entries, cnt = 0; list; list = list->next, cnt++) {
+ e = list->data;
+ if (e->counter_idx >= 0)
+ counters->counters[cnt] = repl->counters[e->counter_idx];
+ }
+ err = iptables_add_counters(table, counters);
+ g_free(counters);
if (err < 0)
- return err;
+ goto out_hash_remove;
- g_hash_table_remove(table_hash, table_name);
+ err = 0;
- return 0;
+out_hash_remove:
+ g_hash_table_remove(table_hash, table_name);
+out_free:
+ g_free(repl->counters);
+ g_free(repl);
+ return err;
}
static void remove_table(gpointer user_data)
diff --git a/src/log.c b/src/log.c
index 32b35bc8..fa8ac31f 100755
--- a/src/log.c
+++ b/src/log.c
@@ -216,6 +216,7 @@ void connman_error(const char *format, ...)
vsyslog(LOG_ERR, format, ap);
va_end(ap);
+ fflush(log_file);
}
/**
@@ -234,6 +235,7 @@ void connman_debug(const char *format, ...)
vsyslog(LOG_DEBUG, format, ap);
va_end(ap);
+ fflush(log_file);
}
static void print_backtrace(unsigned int offset)
diff --git a/src/main.c b/src/main.c
index 21ed25fd..4bc2266b 100755
--- a/src/main.c
+++ b/src/main.c
@@ -59,6 +59,8 @@ static char *default_blacklist[] = {
"vboxnet",
"virbr",
"ifb",
+ "ve-",
+ "vb-",
NULL
};
@@ -67,6 +69,7 @@ static struct {
char **pref_timeservers;
unsigned int *auto_connect;
unsigned int *preferred_techs;
+ unsigned int *always_connected_techs;
char **fallback_nameservers;
unsigned int timeout_inputreq;
unsigned int timeout_browserlaunch;
@@ -76,6 +79,8 @@ static struct {
char **tethering_technologies;
bool persistent_tethering_mode;
bool enable_6to4;
+ char *vendor_class_id;
+ bool enable_online_check;
#if defined TIZEN_EXT
char **cellular_interfaces;
bool tizen_tv_extension;
@@ -85,6 +90,7 @@ static struct {
.pref_timeservers = NULL,
.auto_connect = NULL,
.preferred_techs = NULL,
+ .always_connected_techs = NULL,
.fallback_nameservers = NULL,
.timeout_inputreq = DEFAULT_INPUT_REQUEST_TIMEOUT,
.timeout_browserlaunch = DEFAULT_BROWSER_LAUNCH_TIMEOUT,
@@ -94,6 +100,8 @@ static struct {
.tethering_technologies = NULL,
.persistent_tethering_mode = false,
.enable_6to4 = false,
+ .vendor_class_id = NULL,
+ .enable_online_check = true,
#if defined TIZEN_EXT
.cellular_interfaces = NULL,
.tizen_tv_extension = false,
@@ -103,6 +111,7 @@ static struct {
#define CONF_BG_SCAN "BackgroundScanning"
#define CONF_PREF_TIMESERVERS "FallbackTimeservers"
#define CONF_AUTO_CONNECT "DefaultAutoConnectTechnologies"
+#define CONF_ALWAYS_CONNECTED_TECHS "AlwaysConnectedTechnologies"
#define CONF_PREFERRED_TECHS "PreferredTechnologies"
#define CONF_FALLBACK_NAMESERVERS "FallbackNameservers"
#define CONF_TIMEOUT_INPUTREQ "InputRequestTimeout"
@@ -113,6 +122,8 @@ static struct {
#define CONF_TETHERING_TECHNOLOGIES "TetheringTechnologies"
#define CONF_PERSISTENT_TETHERING_MODE "PersistentTetheringMode"
#define CONF_ENABLE_6TO4 "Enable6to4"
+#define CONF_VENDOR_CLASS_ID "VendorClassID"
+#define CONF_ENABLE_ONLINE_CHECK "EnableOnlineCheck"
#if defined TIZEN_EXT
#define CONF_CELLULAR_INTERFACE "NetworkCellularInterfaceList"
#define CONF_TIZEN_TV_EXT "TizenTVExtension"
@@ -122,6 +133,7 @@ static const char *supported_options[] = {
CONF_BG_SCAN,
CONF_PREF_TIMESERVERS,
CONF_AUTO_CONNECT,
+ CONF_ALWAYS_CONNECTED_TECHS,
CONF_PREFERRED_TECHS,
CONF_FALLBACK_NAMESERVERS,
CONF_TIMEOUT_INPUTREQ,
@@ -132,6 +144,7 @@ static const char *supported_options[] = {
CONF_TETHERING_TECHNOLOGIES,
CONF_PERSISTENT_TETHERING_MODE,
CONF_ENABLE_6TO4,
+ CONF_ENABLE_ONLINE_CHECK,
#if defined TIZEN_EXT
CONF_CELLULAR_INTERFACE,
CONF_TIZEN_TV_EXT,
@@ -298,6 +311,7 @@ static void parse_config(GKeyFile *config)
char **interfaces;
char **str_list;
char **tethering;
+ char *vendor_class_id;
gsize len;
int timeout;
@@ -351,6 +365,17 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
str_list = __connman_config_get_string_list(config, "General",
+ CONF_ALWAYS_CONNECTED_TECHS, &len, &error);
+
+ if (!error)
+ connman_settings.always_connected_techs =
+ parse_service_types(str_list, len);
+
+ g_strfreev(str_list);
+
+ g_clear_error(&error);
+
+ str_list = __connman_config_get_string_list(config, "General",
CONF_FALLBACK_NAMESERVERS, &len, &error);
if (!error)
@@ -424,6 +449,23 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
+ vendor_class_id = __connman_config_get_string(config, "General",
+ CONF_VENDOR_CLASS_ID, &error);
+ if (!error)
+ connman_settings.vendor_class_id = vendor_class_id;
+
+ g_clear_error(&error);
+
+ boolean = __connman_config_get_bool(config, "General",
+ CONF_ENABLE_ONLINE_CHECK, &error);
+ if (!error) {
+ connman_settings.enable_online_check = boolean;
+ if (!boolean)
+ connman_info("Online check disabled by main config.");
+ }
+
+ g_clear_error(&error);
+
#if defined TIZEN_EXT
check_Tizen_configuration(config);
#endif
@@ -539,10 +581,34 @@ static gboolean option_version = FALSE;
static bool parse_debug(const char *key, const char *value,
gpointer user_data, GError **error)
{
- if (value)
- option_debug = g_strdup(value);
- else
+ if (value) {
+ if (option_debug) {
+ char *prev = option_debug;
+
+ option_debug = g_strconcat(prev, ",", value, NULL);
+ g_free(prev);
+ } else {
+ option_debug = g_strdup(value);
+ }
+ } else {
+ g_free(option_debug);
option_debug = g_strdup("*");
+ }
+
+ return true;
+}
+
+static bool parse_noplugin(const char *key, const char *value,
+ gpointer user_data, GError **error)
+{
+ if (option_noplugin) {
+ char *prev = option_noplugin;
+
+ option_noplugin = g_strconcat(prev, ",", value, NULL);
+ g_free(prev);
+ } else {
+ option_noplugin = g_strdup(value);
+ }
return true;
}
@@ -560,7 +626,7 @@ static GOptionEntry options[] = {
"Specify networking interface to ignore", "DEV" },
{ "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
"Specify plugins to load", "NAME,..." },
- { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
+ { "noplugin", 'P', 0, G_OPTION_ARG_CALLBACK, &parse_noplugin,
"Specify plugins not to load", "NAME,..." },
{ "wifi", 'W', 0, G_OPTION_ARG_STRING, &option_wifi,
"Specify driver for WiFi/Supplicant", "NAME" },
@@ -580,6 +646,9 @@ static GOptionEntry options[] = {
const char *connman_option_get_string(const char *key)
{
+ if (g_str_equal(key, CONF_VENDOR_CLASS_ID))
+ return connman_settings.vendor_class_id;
+
if (g_strcmp0(key, "wifi") == 0) {
if (!option_wifi)
return "nl80211,wext";
@@ -607,6 +676,9 @@ bool connman_setting_get_bool(const char *key)
if (g_str_equal(key, CONF_ENABLE_6TO4))
return connman_settings.enable_6to4;
+ if (g_str_equal(key, CONF_ENABLE_ONLINE_CHECK))
+ return connman_settings.enable_online_check;
+
return false;
}
@@ -640,6 +712,9 @@ unsigned int *connman_setting_get_uint_list(const char *key)
if (g_str_equal(key, CONF_PREFERRED_TECHS))
return connman_settings.preferred_techs;
+ if (g_str_equal(key, CONF_ALWAYS_CONNECTED_TECHS))
+ return connman_settings.always_connected_techs;
+
return NULL;
}
@@ -737,7 +812,6 @@ int main(int argc, char *argv[])
__connman_device_init(option_device, option_nodevice);
__connman_ippool_init();
- __connman_iptables_init();
__connman_firewall_init();
__connman_nat_init();
__connman_tethering_init();
@@ -746,7 +820,6 @@ int main(int argc, char *argv[])
__connman_stats_init();
__connman_clock_init();
- __connman_resolver_init(option_dnsproxy);
__connman_ipconfig_init();
__connman_rtnl_init();
__connman_task_init();
@@ -758,6 +831,7 @@ int main(int argc, char *argv[])
__connman_plugin_init(option_plugin, option_noplugin);
+ __connman_resolver_init(option_dnsproxy);
__connman_rtnl_start();
__connman_dhcp_init();
__connman_dhcpv6_init();
@@ -804,7 +878,6 @@ int main(int argc, char *argv[])
__connman_tethering_cleanup();
__connman_nat_cleanup();
__connman_firewall_cleanup();
- __connman_iptables_cleanup();
__connman_peer_service_cleanup();
__connman_peer_cleanup();
__connman_ippool_cleanup();
diff --git a/src/main.conf b/src/main.conf
index d0edbdf7..a2cc1e20 100755
--- a/src/main.conf
+++ b/src/main.conf
@@ -60,8 +60,8 @@ PreferredTechnologies = wifi, ethernet
# Found interfaces will be compared to the list and will
# not be handled by connman, if their first characters
# match any of the list entries. Default value is
-# vmnet,vboxnet,virbr,ifb.
-# NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb
+# vmnet,vboxnet,virbr,ifb,ve-,vb-.
+# NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb,ve-,vb-
NetworkInterfaceBlacklist = veth, vmnet,vboxnet,virbr,usb,rndis,rmnet,rev_rmnet,dummy,seth_td,seth_w
# Allow connman to change the system hostname. This can
@@ -107,4 +107,20 @@ SingleConnectedTechnology = true
# section 4.1).
# Enable6to4 = false
+# Enable use of http get as on online status check.
+# When a service is in a READY state, and is selected as default,
+# ConnMan will issue an HTTP GET request to verify that end-to-end
+# connectivity is successful. Only then the service will be
+# transitioned to ONLINE state.
+# If this setting is false, the default service will remain in READY state.
+# Default value is true.
+# EnableOnlineCheck = false
+
+# List of technologies with AutoConnect = true which are always connected
+# regardless of PreferredTechnologies setting. Default value is empty and
+# will connect a technology only if it is at a higher preference than any
+# other which is already connected.
+# This setting has no effect if SingleConnectedTechnologies is enabled.
+# AlwaysConnectedTechnologies =
+
NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w
diff --git a/src/nat.c b/src/nat.c
index 063f0851..fb557101 100755
--- a/src/nat.c
+++ b/src/nat.c
@@ -25,7 +25,10 @@
#endif
#include <errno.h>
-#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "connman.h"
@@ -42,46 +45,52 @@ struct connman_nat {
static int enable_ip_forward(bool enable)
{
- FILE *f;
+ static char value = 0;
+ int f, err = 0;
- f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
- if (!f)
+ if ((f = open("/proc/sys/net/ipv4/ip_forward", O_CLOEXEC | O_RDWR)) < 0)
return -errno;
- if (enable)
- fprintf(f, "1");
- else
- fprintf(f, "0");
+ if (!value) {
+ if (read(f, &value, sizeof(value)) < 0)
+ value = 0;
- fclose(f);
+ if (lseek(f, 0, SEEK_SET) < 0)
+ return -errno;
+ }
- return 0;
+ if (enable) {
+ char allow = '1';
+
+ if (write (f, &allow, sizeof(allow)) < 0)
+ err = -errno;
+ } else {
+ char deny = '0';
+
+ if (value)
+ deny = value;
+
+ if (write(f, &deny, sizeof(deny)) < 0)
+ err = -errno;
+
+ value = 0;
+ }
+
+ close(f);
+
+ return err;
}
static int enable_nat(struct connman_nat *nat)
{
- char *cmd;
- int err;
-
g_free(nat->interface);
nat->interface = g_strdup(default_interface);
if (!nat->interface)
return 0;
- /* Enable masquerading */
- cmd = g_strdup_printf("-s %s/%d -o %s -j MASQUERADE",
- nat->address,
- nat->prefixlen,
- nat->interface);
-
- err = __connman_firewall_add_rule(nat->fw, "nat",
- "POSTROUTING", cmd);
- g_free(cmd);
- if (err < 0)
- return err;
-
- return __connman_firewall_enable(nat->fw);
+ return __connman_firewall_enable_nat(nat->fw, nat->address,
+ nat->prefixlen, nat->interface);
}
static void disable_nat(struct connman_nat *nat)
@@ -89,8 +98,7 @@ static void disable_nat(struct connman_nat *nat)
if (!nat->interface)
return;
- /* Disable masquerading */
- __connman_firewall_disable(nat->fw);
+ __connman_firewall_disable_nat(nat->fw);
}
int __connman_nat_enable(const char *name, const char *address,
diff --git a/src/network.c b/src/network.c
index f7a9925a..d38fc0af 100755
--- a/src/network.c
+++ b/src/network.c
@@ -90,8 +90,13 @@ struct connman_network {
char *passphrase;
char *eap;
char *identity;
+ char *anonymous_identity;
char *agent_identity;
char *ca_cert_path;
+ char *subject_match;
+ char *altsubject_match;
+ char *domain_suffix_match;
+ char *domain_match;
char *client_cert_path;
char *private_key_path;
char *private_key_passphrase;
@@ -109,7 +114,8 @@ struct connman_network {
bool rsn_mode;
int disconnect_reason;
int assoc_status_code;
- GSList *vsie_list;
+ void *wifi_vsie;
+ unsigned int wifi_vsie_len;
#endif
} wifi;
@@ -164,8 +170,6 @@ static void set_configuration(struct connman_network *network,
__connman_device_set_network(network->device, network);
- connman_device_set_disconnected(network->device, false);
-
service = connman_service_lookup_from_network(network);
__connman_service_ipconfig_indicate_state(service,
CONNMAN_SERVICE_STATE_CONFIGURATION,
@@ -201,6 +205,8 @@ static void dhcp_success(struct connman_network *network)
if (err < 0)
goto err;
+ __connman_service_save(service);
+
return;
err:
@@ -251,8 +257,8 @@ static int set_connected_manual(struct connman_network *network)
network->connecting = false;
service = connman_service_lookup_from_network(network);
-
ipconfig = __connman_service_get_ip4config(service);
+ __connman_ipconfig_enable(ipconfig);
if (!__connman_ipconfig_get_local(ipconfig))
__connman_service_read_ip4config(service);
@@ -283,6 +289,7 @@ static int set_connected_dhcp(struct connman_network *network)
service = connman_service_lookup_from_network(network);
ipconfig_ipv4 = __connman_service_get_ip4config(service);
+ __connman_ipconfig_enable(ipconfig_ipv4);
err = __connman_dhcp_start(ipconfig_ipv4, network,
dhcp_callback, NULL);
@@ -326,13 +333,8 @@ static int manual_ipv6_set(struct connman_network *network,
if (err < 0)
return err;
- __connman_connection_gateway_activate(service,
- CONNMAN_IPCONFIG_TYPE_IPV6);
-
__connman_device_set_network(network->device, network);
- connman_device_set_disconnected(network->device, false);
-
connman_network_set_associating(network, false);
network->connecting = false;
@@ -613,8 +615,6 @@ static void autoconf_ipv6_set(struct connman_network *network)
__connman_device_set_network(network->device, network);
- connman_device_set_disconnected(network->device, false);
-
#if defined TIZEN_EXT
if(network->type == CONNMAN_NETWORK_TYPE_CELLULAR)
return;
@@ -628,6 +628,8 @@ static void autoconf_ipv6_set(struct connman_network *network)
if (!ipconfig)
return;
+ __connman_ipconfig_enable(ipconfig);
+
__connman_ipconfig_enable_ipv6(ipconfig);
__connman_ipconfig_address_remove(ipconfig);
@@ -710,10 +712,20 @@ static void set_disconnected(struct connman_network *network)
switch (ipv4_method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
- case CONNMAN_IPCONFIG_METHOD_AUTO:
case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
break;
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ /*
+ * If the current method is AUTO then next time we
+ * try first DHCP. DHCP also needs to be stopped
+ * in this case because if we fell in AUTO means
+ * that DHCP was launched for IPv4 but it failed.
+ */
+ __connman_ipconfig_set_method(ipconfig_ipv4,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
+ __connman_service_notify_ipv4_configuration(service);
+ /* fall through */
case CONNMAN_IPCONFIG_METHOD_DHCP:
__connman_dhcp_stop(ipconfig_ipv4);
break;
@@ -895,20 +907,6 @@ static void probe_driver(struct connman_network_driver *driver)
}
}
-static void remove_driver(struct connman_network_driver *driver)
-{
- GSList *list;
-
- DBG("driver %p name %s", driver, driver->name);
-
- for (list = network_list; list; list = list->next) {
- struct connman_network *network = list->data;
-
- if (network->driver == driver)
- network_remove(network);
- }
-}
-
static gint compare_priority(gconstpointer a, gconstpointer b)
{
const struct connman_network_driver *driver1 = a;
@@ -945,11 +943,18 @@ int connman_network_driver_register(struct connman_network_driver *driver)
*/
void connman_network_driver_unregister(struct connman_network_driver *driver)
{
+ GSList *list;
+
DBG("driver %p name %s", driver, driver->name);
driver_list = g_slist_remove(driver_list, driver);
- remove_driver(driver);
+ for (list = network_list; list; list = list->next) {
+ struct connman_network *network = list->data;
+
+ if (network->driver == driver)
+ network_remove(network);
+ }
}
static void network_destruct(struct connman_network *network)
@@ -962,15 +967,20 @@ static void network_destruct(struct connman_network *network)
g_free(network->wifi.passphrase);
g_free(network->wifi.eap);
g_free(network->wifi.identity);
+ g_free(network->wifi.anonymous_identity);
g_free(network->wifi.agent_identity);
g_free(network->wifi.ca_cert_path);
+ g_free(network->wifi.subject_match);
+ g_free(network->wifi.altsubject_match);
+ g_free(network->wifi.domain_suffix_match);
+ g_free(network->wifi.domain_match);
g_free(network->wifi.client_cert_path);
g_free(network->wifi.private_key_path);
g_free(network->wifi.private_key_passphrase);
g_free(network->wifi.phase2_auth);
g_free(network->wifi.pin_wps);
#if defined TIZEN_EXT
- g_slist_free_full(network->wifi.vsie_list, g_free);
+ g_free(network->wifi.wifi_vsie);
#endif
g_free(network->path);
g_free(network->group);
@@ -997,14 +1007,10 @@ struct connman_network *connman_network_create(const char *identifier,
struct connman_network *network;
char *ident;
- DBG("identifier %s type %d", identifier, type);
-
network = g_try_new0(struct connman_network, 1);
if (!network)
return NULL;
- DBG("network %p", network);
-
network->refcount = 1;
ident = g_strdup(identifier);
@@ -1019,6 +1025,8 @@ struct connman_network *connman_network_create(const char *identifier,
network_list = g_slist_prepend(network_list, network);
+ DBG("network %p identifier %s type %s", network, identifier,
+ type2string(type));
return network;
}
@@ -2058,18 +2066,6 @@ int connman_network_get_disconnect_reason(struct connman_network *network)
return network->wifi.disconnect_reason;
}
-
-int connman_network_set_assoc_status_code(struct connman_network *network,
- int assoc_status_code)
-{
-
- if (network == NULL)
- return 0;
-
- network->wifi.assoc_status_code = assoc_status_code;
- return 0;
-}
-
int connman_network_get_assoc_status_code(struct connman_network *network)
{
if (network == NULL)
@@ -2077,7 +2073,6 @@ int connman_network_get_assoc_status_code(struct connman_network *network)
return network->wifi.assoc_status_code;
}
-
#endif
int connman_network_set_nameservers(struct connman_network *network,
@@ -2161,10 +2156,6 @@ int connman_network_set_name(struct connman_network *network,
int connman_network_set_strength(struct connman_network *network,
uint8_t strength)
{
-#if !defined TIZEN_EXT
- DBG("network %p strengh %d", network, strength);
-#endif
-
network->strength = strength;
return 0;
@@ -2178,10 +2169,6 @@ uint8_t connman_network_get_strength(struct connman_network *network)
int connman_network_set_frequency(struct connman_network *network,
uint16_t frequency)
{
-#if !defined TIZEN_EXT
- DBG("network %p frequency %d", network, frequency);
-#endif
-
network->frequency = frequency;
return 0;
@@ -2195,8 +2182,6 @@ uint16_t connman_network_get_frequency(struct connman_network *network)
int connman_network_set_wifi_channel(struct connman_network *network,
uint16_t channel)
{
- DBG("network %p wifi channel %d", network, channel);
-
network->wifi.channel = channel;
return 0;
@@ -2218,10 +2203,6 @@ uint16_t connman_network_get_wifi_channel(struct connman_network *network)
int connman_network_set_string(struct connman_network *network,
const char *key, const char *value)
{
-#if !defined TIZEN_EXT
- DBG("network %p key %s value %s", network, key, value);
-#endif
-
if (g_strcmp0(key, "Name") == 0)
return connman_network_set_name(network, value);
@@ -2249,12 +2230,27 @@ int connman_network_set_string(struct connman_network *network,
} else if (g_str_equal(key, "WiFi.Identity")) {
g_free(network->wifi.identity);
network->wifi.identity = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.AnonymousIdentity")) {
+ g_free(network->wifi.anonymous_identity);
+ network->wifi.anonymous_identity = g_strdup(value);
} else if (g_str_equal(key, "WiFi.AgentIdentity")) {
g_free(network->wifi.agent_identity);
network->wifi.agent_identity = g_strdup(value);
} else if (g_str_equal(key, "WiFi.CACertFile")) {
g_free(network->wifi.ca_cert_path);
network->wifi.ca_cert_path = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.SubjectMatch")) {
+ g_free(network->wifi.subject_match);
+ network->wifi.subject_match = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.AltSubjectMatch")) {
+ g_free(network->wifi.altsubject_match);
+ network->wifi.altsubject_match = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.DomainSuffixMatch")) {
+ g_free(network->wifi.domain_suffix_match);
+ network->wifi.domain_suffix_match = g_strdup(value);
+ } else if (g_str_equal(key, "WiFi.DomainMatch")) {
+ g_free(network->wifi.domain_match);
+ network->wifi.domain_match = g_strdup(value);
} else if (g_str_equal(key, "WiFi.ClientCertFile")) {
g_free(network->wifi.client_cert_path);
network->wifi.client_cert_path = g_strdup(value);
@@ -2287,10 +2283,6 @@ int connman_network_set_string(struct connman_network *network,
const char *connman_network_get_string(struct connman_network *network,
const char *key)
{
-#if !defined TIZEN_EXT
- DBG("network %p key %s", network, key);
-#endif
-
if (g_str_equal(key, "Path"))
return network->path;
else if (g_str_equal(key, "Name"))
@@ -2315,10 +2307,20 @@ const char *connman_network_get_string(struct connman_network *network,
return network->wifi.eap;
else if (g_str_equal(key, "WiFi.Identity"))
return network->wifi.identity;
+ else if (g_str_equal(key, "WiFi.AnonymousIdentity"))
+ return network->wifi.anonymous_identity;
else if (g_str_equal(key, "WiFi.AgentIdentity"))
return network->wifi.agent_identity;
else if (g_str_equal(key, "WiFi.CACertFile"))
return network->wifi.ca_cert_path;
+ else if (g_str_equal(key, "WiFi.SubjectMatch"))
+ return network->wifi.subject_match;
+ else if (g_str_equal(key, "WiFi.AltSubjectMatch"))
+ return network->wifi.altsubject_match;
+ else if (g_str_equal(key, "WiFi.DomainSuffixMatch"))
+ return network->wifi.domain_suffix_match;
+ else if (g_str_equal(key, "WiFi.DomainMatch"))
+ return network->wifi.domain_match;
else if (g_str_equal(key, "WiFi.ClientCertFile"))
return network->wifi.client_cert_path;
else if (g_str_equal(key, "WiFi.PrivateKeyFile"))
@@ -2344,10 +2346,6 @@ const char *connman_network_get_string(struct connman_network *network,
int connman_network_set_bool(struct connman_network *network,
const char *key, bool value)
{
-#if !defined TIZEN_EXT
- DBG("network %p key %s value %d", network, key, value);
-#endif
-
if (g_strcmp0(key, "Roaming") == 0)
network->roaming = value;
else if (g_strcmp0(key, "WiFi.WPS") == 0)
@@ -2374,10 +2372,6 @@ int connman_network_set_bool(struct connman_network *network,
bool connman_network_get_bool(struct connman_network *network,
const char *key)
{
-#if !defined TIZEN_EXT
- DBG("network %p key %s", network, key);
-#endif
-
if (g_str_equal(key, "Roaming"))
return network->roaming;
else if (g_str_equal(key, "WiFi.WPS"))
@@ -2394,31 +2388,6 @@ bool connman_network_get_bool(struct connman_network *network,
return false;
}
-#if defined TIZEN_EXT
-/**
- * connman_network_set_vsie_list:
- * @network: network structure
- * @vsie_list: GSList pointer
- *
- * Set vendor specific list pointer
- */
-void connman_network_set_vsie_list(struct connman_network *network, GSList *vsie_list)
-{
- network->wifi.vsie_list = vsie_list;
-}
-
-/**
- * connman_network_get_vsie_list:
- * @network: network structure
- *
- * Get vendor specific list pointer
- */
-void *connman_network_get_vsie_list(struct connman_network *network)
-{
- return network->wifi.vsie_list;
-}
-#endif
-
/**
* connman_network_set_blob:
* @network: network structure
@@ -2431,10 +2400,6 @@ void *connman_network_get_vsie_list(struct connman_network *network)
int connman_network_set_blob(struct connman_network *network,
const char *key, const void *data, unsigned int size)
{
-#if !defined TIZEN_EXT
- DBG("network %p key %s size %d", network, key, size);
-#endif
-
if (g_str_equal(key, "WiFi.SSID")) {
g_free(network->wifi.ssid);
network->wifi.ssid = g_try_malloc(size);
@@ -2443,6 +2408,16 @@ int connman_network_set_blob(struct connman_network *network,
network->wifi.ssid_len = size;
} else
network->wifi.ssid_len = 0;
+#if defined TIZEN_EXT
+ } else if (g_str_equal(key, "WiFi.Vsie")){
+ g_free(network->wifi.wifi_vsie);
+ network->wifi.wifi_vsie = g_try_malloc(size);
+ if (network->wifi.wifi_vsie) {
+ memcpy(network->wifi.wifi_vsie, data, size);
+ network->wifi.wifi_vsie_len = size;
+ } else
+ network->wifi.wifi_vsie_len = 0;
+#endif
} else {
return -EINVAL;
}
@@ -2461,16 +2436,21 @@ int connman_network_set_blob(struct connman_network *network,
const void *connman_network_get_blob(struct connman_network *network,
const char *key, unsigned int *size)
{
-#if !defined TIZEN_EXT
- DBG("network %p key %s", network, key);
-#endif
-
if (g_str_equal(key, "WiFi.SSID")) {
if (size)
*size = network->wifi.ssid_len;
return network->wifi.ssid;
}
+#if defined TIZEN_EXT
+ if (g_str_equal(key, "WiFi.Vsie")) {
+ if (size)
+ *size = network->wifi.wifi_vsie_len;
+
+ return network->wifi.wifi_vsie;
+ }
+#endif
+
return NULL;
}
diff --git a/src/ntp.c b/src/ntp.c
index bc553bf3..11512a02 100755
--- a/src/ntp.c
+++ b/src/ntp.c
@@ -30,10 +30,12 @@
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
+#include <sys/timex.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
+#include <netdb.h>
#include <glib.h>
@@ -65,9 +67,13 @@ struct ntp_msg {
#define OFFSET_1900_1970 2208988800UL /* 1970 - 1900 in seconds */
-#define STEPTIME_MIN_OFFSET 0.128
+#define STEPTIME_MIN_OFFSET 0.4
#define LOGTOD(a) ((a) < 0 ? 1. / (1L << -(a)) : 1L << (int)(a))
+#define NSEC_PER_SEC ((uint64_t)1000000000ULL)
+#ifndef ADJ_SETOFFSET
+#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
+#endif
#define NTP_SEND_TIMEOUT 2
#define NTP_SEND_RETRIES 3
@@ -117,12 +123,12 @@ static struct timespec mtx_time;
static int transmit_fd = 0;
static char *timeserver = NULL;
-static struct sockaddr_in timeserver_addr;
+static struct sockaddr_in6 timeserver_addr;
static gint poll_id = 0;
static gint timeout_id = 0;
static guint retries = 0;
-static void send_packet(int fd, const char *server, uint32_t timeout);
+static void send_packet(int fd, struct sockaddr *server, uint32_t timeout);
static void next_server(void)
{
@@ -143,17 +149,19 @@ static gboolean send_timeout(gpointer user_data)
if (retries++ == NTP_SEND_RETRIES)
next_server();
else
- send_packet(transmit_fd, timeserver, timeout << 1);
+ send_packet(transmit_fd, (struct sockaddr *)&timeserver_addr, timeout << 1);
return FALSE;
}
-static void send_packet(int fd, const char *server, uint32_t timeout)
+static void send_packet(int fd, struct sockaddr *server, uint32_t timeout)
{
struct ntp_msg msg;
- struct sockaddr_in addr;
struct timeval transmit_timeval;
ssize_t len;
+ void * addr;
+ int size;
+ char ipaddrstring[INET6_ADDRSTRLEN + 1];
/*
* At some point, we could specify the actual system precision with:
@@ -164,14 +172,19 @@ static void send_packet(int fd, const char *server, uint32_t timeout)
memset(&msg, 0, sizeof(msg));
msg.flags = NTP_FLAGS_ENCODE(NTP_FLAG_LI_NOTINSYNC, NTP_FLAG_VN_VER4,
NTP_FLAG_MD_CLIENT);
- msg.poll = 4; // min
- msg.poll = 10; // max
+ msg.poll = 10;
msg.precision = NTP_PRECISION_S;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(123);
- addr.sin_addr.s_addr = inet_addr(server);
+ if (server->sa_family == AF_INET) {
+ size = sizeof(struct sockaddr_in);
+ addr = (void *)&(((struct sockaddr_in *)&timeserver_addr)->sin_addr);
+ } else if (server->sa_family == AF_INET6) {
+ size = sizeof(struct sockaddr_in6);
+ addr = (void *)&timeserver_addr.sin6_addr;
+ } else {
+ connman_error("Family is neither ipv4 nor ipv6");
+ return;
+ }
gettimeofday(&transmit_timeval, NULL);
clock_gettime(CLOCK_MONOTONIC, &mtx_time);
@@ -180,10 +193,12 @@ static void send_packet(int fd, const char *server, uint32_t timeout)
msg.xmttime.fraction = htonl(transmit_timeval.tv_usec * 1000);
len = sendto(fd, &msg, sizeof(msg), MSG_DONTWAIT,
- &addr, sizeof(addr));
+ server, size);
+
if (len < 0) {
connman_error("Time request for server %s failed (%d/%s)",
- server, errno, strerror(errno));
+ inet_ntop(server->sa_family, addr, ipaddrstring, sizeof(ipaddrstring)),
+ errno, strerror(errno));
if (errno == ENETUNREACH)
__connman_timeserver_sync_next();
@@ -192,7 +207,8 @@ static void send_packet(int fd, const char *server, uint32_t timeout)
}
if (len != sizeof(msg)) {
- connman_error("Broken time request for server %s", server);
+ connman_error("Broken time request for server %s",
+ inet_ntop(server->sa_family, addr, ipaddrstring, sizeof(ipaddrstring)));
return;
}
@@ -213,7 +229,7 @@ static gboolean next_poll(gpointer user_data)
if (!timeserver || transmit_fd == 0)
return FALSE;
- send_packet(transmit_fd, timeserver, NTP_SEND_TIMEOUT);
+ send_packet(transmit_fd, (struct sockaddr *)&timeserver_addr, NTP_SEND_TIMEOUT);
return FALSE;
}
@@ -235,7 +251,9 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
double m_delta, org, rec, xmt, dst;
double delay, offset;
static guint transmit_delay;
-
+#if !defined TIZEN_EXT
+ struct timex tmx = {};
+#endif
if (len < sizeof(*msg)) {
connman_error("Invalid response from time server");
return;
@@ -324,8 +342,6 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
poll_id = g_timeout_add_seconds(transmit_delay, next_poll, NULL);
- connman_info("ntp: time slew %+.6f s", offset);
-
#if defined TIZEN_EXT
//send the dbus message to alram-manager
{
@@ -387,37 +403,44 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
}
#else
if (offset < STEPTIME_MIN_OFFSET && offset > -STEPTIME_MIN_OFFSET) {
- struct timeval adj;
-
- adj.tv_sec = (long) offset;
- adj.tv_usec = (offset - adj.tv_sec) * 1000000;
-
- DBG("adjusting time");
-
- if (adjtime(&adj, &adj) < 0) {
- connman_error("Failed to adjust time");
- return;
- }
-
- DBG("%lu seconds, %lu msecs", adj.tv_sec, adj.tv_usec);
+ tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR;
+ tmx.status = STA_PLL;
+ tmx.offset = offset * NSEC_PER_SEC;
+ tmx.constant = msg->poll - 4;
+ tmx.maxerror = 0;
+ tmx.esterror = 0;
+
+ connman_info("ntp: adjust (slew): %+.6f sec", offset);
} else {
- struct timeval cur;
- double dtime;
-
- gettimeofday(&cur, NULL);
- dtime = offset + cur.tv_sec + 1.0e-6 * cur.tv_usec;
- cur.tv_sec = (long) dtime;
- cur.tv_usec = (dtime - cur.tv_sec) * 1000000;
+ tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET | ADJ_MAXERROR | ADJ_ESTERROR;
+
+ /* ADJ_NANO uses nanoseconds in the microseconds field */
+ tmx.time.tv_sec = (long)offset;
+ tmx.time.tv_usec = (offset - tmx.time.tv_sec) * NSEC_PER_SEC;
+ tmx.maxerror = 0;
+ tmx.esterror = 0;
+
+ /* the kernel expects -0.3s as {-1, 7000.000.000} */
+ if (tmx.time.tv_usec < 0) {
+ tmx.time.tv_sec -= 1;
+ tmx.time.tv_usec += NSEC_PER_SEC;
+ }
- DBG("setting time");
+ connman_info("ntp: adjust (jump): %+.6f sec", offset);
+ }
- if (settimeofday(&cur, NULL) < 0) {
- connman_error("Failed to set time");
- return;
- }
+ if (NTP_FLAGS_LI_DECODE(msg->flags) & NTP_FLAG_LI_ADDSECOND)
+ tmx.status |= STA_INS;
+ else if (NTP_FLAGS_LI_DECODE(msg->flags) & NTP_FLAG_LI_DELSECOND)
+ tmx.status |= STA_DEL;
- DBG("%lu seconds, %lu msecs", cur.tv_sec, cur.tv_usec);
+ if (adjtimex(&tmx) < 0) {
+ connman_error("Failed to adjust time");
+ return;
}
+
+ DBG("interval/delta/delay/drift %fs/%+.3fs/%.3fs/%+ldppm",
+ LOGTOD(msg->poll), offset, delay, tmx.freq / 65536);
#endif
}
@@ -425,7 +448,7 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
unsigned char buf[128];
- struct sockaddr_in sender_addr;
+ struct sockaddr_in6 sender_addr;
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
@@ -434,6 +457,9 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
char aux[128];
ssize_t len;
int fd;
+ int size;
+ void * addr_ptr;
+ void * src_ptr;
if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
connman_error("Problem with timer server channel");
@@ -458,8 +484,20 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
if (len < 0)
return TRUE;
- if (timeserver_addr.sin_addr.s_addr != sender_addr.sin_addr.s_addr)
- /* only accept messages from the timeserver */
+ if (sender_addr.sin6_family == AF_INET) {
+ size = 4;
+ addr_ptr = &((struct sockaddr_in *)&timeserver_addr)->sin_addr;
+ src_ptr = &((struct sockaddr_in *)&sender_addr)->sin_addr;
+ } else if (sender_addr.sin6_family == AF_INET6) {
+ size = 16;
+ addr_ptr = &((struct sockaddr_in6 *)&timeserver_addr)->sin6_addr;
+ src_ptr = &((struct sockaddr_in6 *)&sender_addr)->sin6_addr;
+ } else {
+ connman_error("Not a valid family type");
+ return TRUE;
+ }
+
+ if(memcmp(addr_ptr, src_ptr, size) != 0)
return TRUE;
tv = NULL;
@@ -484,36 +522,76 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
static void start_ntp(char *server)
{
GIOChannel *channel;
- struct sockaddr_in addr;
+ struct addrinfo hint;
+ struct addrinfo *info;
+ struct sockaddr * addr;
+ struct sockaddr_in * in4addr;
+ struct sockaddr_in6 in6addr;
+ int size;
+ int family;
int tos = IPTOS_LOWDELAY, timestamp = 1;
+ int ret;
if (!server)
return;
- DBG("server %s", server);
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_socktype = SOCK_DGRAM;
+ hint.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
+ ret = getaddrinfo(server, NULL, &hint, &info);
- if (channel_watch > 0)
- goto send;
+ if (ret) {
+ connman_error("cannot get server info");
+ return;
+ }
- transmit_fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (transmit_fd < 0) {
- connman_error("Failed to open time server socket");
+ family = info->ai_family;
+
+ memcpy(&timeserver_addr, info->ai_addr, info->ai_addrlen);
+ freeaddrinfo(info);
+ memset(&in6addr, 0, sizeof(in6addr));
+
+ if (family == AF_INET) {
+ ((struct sockaddr_in *)&timeserver_addr)->sin_port = htons(123);
+ in4addr = (struct sockaddr_in *)&in6addr;
+ in4addr->sin_family = family;
+ addr = (struct sockaddr *)in4addr;
+ size = sizeof(struct sockaddr_in);
+ } else if (family == AF_INET6) {
+ timeserver_addr.sin6_port = htons(123);
+ in6addr.sin6_family = family;
+ addr = (struct sockaddr *)&in6addr;
+ size = sizeof(in6addr);
+ } else {
+ connman_error("Family is neither ipv4 nor ipv6");
return;
}
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
+ DBG("server %s family %d", server, family);
- if (bind(transmit_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (channel_watch > 0)
+ goto send;
+
+ transmit_fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+
+ if (transmit_fd <= 0) {
+ connman_error("Failed to open time server socket");
+ return;
+ }
+
+ if (bind(transmit_fd, (struct sockaddr *) addr, size) < 0) {
connman_error("Failed to bind time server socket");
close(transmit_fd);
return;
}
- if (setsockopt(transmit_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
- connman_error("Failed to set type of service option");
- close(transmit_fd);
- return;
+ if (family == AF_INET) {
+ if (setsockopt(transmit_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
+ connman_error("Failed to set type of service option");
+ close(transmit_fd);
+ return;
+ }
}
if (setsockopt(transmit_fd, SOL_SOCKET, SO_TIMESTAMP, &timestamp,
@@ -541,7 +619,7 @@ static void start_ntp(char *server)
g_io_channel_unref(channel);
send:
- send_packet(transmit_fd, server, NTP_SEND_TIMEOUT);
+ send_packet(transmit_fd, (struct sockaddr*)&timeserver_addr, NTP_SEND_TIMEOUT);
}
int __connman_ntp_start(char *server)
@@ -555,7 +633,6 @@ int __connman_ntp_start(char *server)
g_free(timeserver);
timeserver = g_strdup(server);
- timeserver_addr.sin_addr.s_addr = inet_addr(server);
start_ntp(timeserver);
diff --git a/src/peer.c b/src/peer.c
index 206b799b..340cbcc2 100755
--- a/src/peer.c
+++ b/src/peer.c
@@ -176,7 +176,7 @@ static int start_dhcp_server(struct connman_peer *peer)
if (err < 0)
goto error;
- g_timeout_add_seconds(0, dhcp_server_started, connman_peer_ref(peer));
+ g_idle_add(dhcp_server_started, connman_peer_ref(peer));
return 0;
@@ -758,7 +758,7 @@ void connman_peer_set_name(struct connman_peer *peer, const char *name)
void connman_peer_set_iface_address(struct connman_peer *peer,
const unsigned char *iface_address)
{
- memset(peer->iface_address, 0, ETH_ALEN);
+ memset(peer->iface_address, 0, sizeof(peer->iface_address));
memcpy(peer->iface_address, iface_address, ETH_ALEN);
}
@@ -905,13 +905,16 @@ int connman_peer_set_state(struct connman_peer *peer,
break;
case CONNMAN_PEER_STATE_READY:
reply_pending(peer, 0);
+ __connman_technology_set_connected(CONNMAN_SERVICE_TYPE_P2P, true);
break;
case CONNMAN_PEER_STATE_DISCONNECT:
if (peer->connection_master)
stop_dhcp_server(peer);
+ else
+ __connman_dhcp_stop(peer->ipconfig);
peer->connection_master = false;
peer->sub_device = NULL;
-
+ __connman_technology_set_connected(CONNMAN_SERVICE_TYPE_P2P, false);
break;
case CONNMAN_PEER_STATE_FAILURE:
if (manage_peer_error(peer) == 0)
diff --git a/src/peer_service.c b/src/peer_service.c
index 053672af..a457bff7 100755
--- a/src/peer_service.c
+++ b/src/peer_service.c
@@ -293,9 +293,6 @@ int __connman_peer_service_register(const char *owner, DBusMessage *msg,
if (service) {
DBG("Found one existing service %p", service);
- if (g_strcmp0(service->owner, owner))
- ret = -EBUSY;
-
if (service->pending)
ret = -EINPROGRESS;
else
diff --git a/src/provider.c b/src/provider.c
index 521346b4..c0d69e49 100755
--- a/src/provider.c
+++ b/src/provider.c
@@ -141,12 +141,12 @@ int connman_provider_disconnect(struct connman_provider *provider)
provider_indicate_state(provider,
CONNMAN_SERVICE_STATE_DISCONNECT);
- if (err < 0) {
- if (err != -EINPROGRESS)
- return err;
+ if (err < 0)
+ return err;
- return -EINPROGRESS;
- }
+ if (provider->vpn_service)
+ provider_indicate_state(provider,
+ CONNMAN_SERVICE_STATE_IDLE);
return 0;
}
@@ -164,14 +164,15 @@ int connman_provider_remove(struct connman_provider *provider)
return 0;
}
-int __connman_provider_connect(struct connman_provider *provider)
+int __connman_provider_connect(struct connman_provider *provider,
+ const char *dbus_sender)
{
int err;
DBG("provider %p", provider);
if (provider->driver && provider->driver->connect)
- err = provider->driver->connect(provider);
+ err = provider->driver->connect(provider, dbus_sender);
else
return -EOPNOTSUPP;
diff --git a/src/proxy.c b/src/proxy.c
index f331de92..e1bc420a 100755
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -123,7 +123,7 @@ unsigned int connman_proxy_lookup(const char *interface, const char *url,
lookup->url = g_strdup(url);
lookup->service = connman_service_ref(service);
- lookup->watch = g_timeout_add_seconds(0, lookup_callback, lookup);
+ lookup->watch = g_idle_add(lookup_callback, lookup);
if (lookup->watch == 0) {
g_free(lookup->url);
g_free(lookup);
diff --git a/src/resolver.c b/src/resolver.c
index 8a7fa663..d6c20cdd 100755
--- a/src/resolver.c
+++ b/src/resolver.c
@@ -97,9 +97,9 @@ static int resolvfile_export(void)
* MAXDNSRCH/MAXNS entries are used.
*/
- for (count = 0, list = g_list_last(resolvfile_list);
+ for (count = 0, list = g_list_first(resolvfile_list);
list && (count < MAXDNSRCH);
- list = g_list_previous(list)) {
+ list = g_list_next(list)) {
struct resolvfile_entry *entry = list->data;
if (!entry->domain)
@@ -115,9 +115,9 @@ static int resolvfile_export(void)
if (count)
g_string_append_printf(content, "\n");
- for (count = 0, list = g_list_last(resolvfile_list);
+ for (count = 0, list = g_list_first(resolvfile_list);
list && (count < MAXNS);
- list = g_list_previous(list)) {
+ list = g_list_next(list)) {
struct resolvfile_entry *entry = list->data;
if (!entry->server)
@@ -207,7 +207,7 @@ int __connman_resolvfile_remove(int index, const char *domain,
return resolvfile_export();
}
-static void append_fallback_nameservers(void)
+void __connman_resolver_append_fallback_nameservers(void)
{
GSList *list;
@@ -284,7 +284,7 @@ static void remove_entries(GSList *entries)
g_slist_free(entries);
- append_fallback_nameservers();
+ __connman_resolver_append_fallback_nameservers();
}
static gboolean resolver_expire_cb(gpointer user_data)
@@ -389,24 +389,6 @@ static int append_resolver(int index, const char *domain,
entry->timeout = g_timeout_add_seconds(interval,
resolver_refresh_cb, entry);
-
- /*
- * We update the service only for those nameservers
- * that are automagically added via netlink (lifetime > 0)
- */
- if (server && entry->index >= 0) {
- struct connman_service *service;
- service = __connman_service_lookup_from_index(entry->index);
- if (service)
-#if defined TIZEN_EXT
- __connman_service_nameserver_append(service,
- server, true,
- CONNMAN_IPCONFIG_TYPE_ALL);
-#else
- __connman_service_nameserver_append(service,
- server, true);
-#endif
- }
}
if (entry->index >= 0 && entry->server)
@@ -419,6 +401,24 @@ static int append_resolver(int index, const char *domain,
else
__connman_resolvfile_append(entry->index, domain, server);
+ /*
+ * We update the service only for those nameservers
+ * that are automagically added via netlink (lifetime > 0)
+ */
+ if (server && entry->index >= 0 && lifetime) {
+ struct connman_service *service;
+ service = __connman_service_lookup_from_index(entry->index);
+ if (service)
+#if defined TIZEN_EXT
+ __connman_service_nameserver_append(service,
+ server, true,
+ CONNMAN_IPCONFIG_TYPE_ALL);
+#else
+ __connman_service_nameserver_append(service,
+ server, true);
+#endif
+ }
+
return 0;
}
@@ -617,6 +617,28 @@ int __connman_resolver_redo_servers(int index)
entry->server);
}
+ /*
+ * We want to re-add all search domains back to search
+ * domain lists as they just got removed for RDNSS IPv6-servers
+ * (above).
+ * Removal of search domains is not necessary
+ * as there can be only one instance of each search domain
+ * in the each dns-servers search domain list.
+ */
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (entry->index != index)
+ continue;
+
+ if (entry->server)
+ continue;
+
+ __connman_dnsproxy_append(entry->index, entry->domain,
+ NULL);
+ }
+
return 0;
}
@@ -643,6 +665,14 @@ int __connman_resolver_init(gboolean dnsproxy)
DBG("dnsproxy %d", dnsproxy);
+ /* get autoip nameservers */
+ ns = __connman_inet_get_pnp_nameservers(NULL);
+ for (i = 0; ns && ns[i]; i += 1) {
+ DBG("pnp server %s", ns[i]);
+ append_resolver(i, NULL, ns[i], 86400, 0);
+ }
+ g_strfreev(ns);
+
if (!dnsproxy)
return 0;
diff --git a/src/rfkill.c b/src/rfkill.c
index 36426e00..fce9d720 100755
--- a/src/rfkill.c
+++ b/src/rfkill.c
@@ -206,7 +206,7 @@ int __connman_rfkill_init(void)
DBG("");
- fd = open("/dev/rfkill", O_RDWR | O_CLOEXEC);
+ fd = open("/dev/rfkill", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
connman_error("Failed to open RFKILL control device");
return -EIO;
diff --git a/src/rtnl.c b/src/rtnl.c
index 5690c48e..35ae0a96 100755
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -212,7 +212,9 @@ static void read_uevent(struct interface_data *interface)
} else if (strcmp(line + 8, "vlan") == 0) {
interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
-
+ } else if (strcmp(line + 8, "bond") == 0) {
+ interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
+ interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
} else {
interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN;
@@ -551,7 +553,9 @@ static void process_newlink(unsigned short type, int index, unsigned flags,
interface = NULL;
#endif
- } else
+ } else if (type == ARPHRD_ETHER && interface->device_type == CONNMAN_DEVICE_TYPE_UNKNOWN)
+ read_uevent(interface);
+ else
interface = NULL;
for (list = rtnl_list; list; list = list->next) {
@@ -1355,7 +1359,12 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr)
if (opt->nd_opt_type == 25) { /* ND_OPT_RDNSS */
char buf[40];
+#if defined TIZEN_EXT
+ struct connman_service *service;
+ service = __connman_service_lookup_from_index(index);
+ DBG("service: %p\n",service);
+#endif
servers = rtnl_nd_opt_rdnss(opt, &lifetime,
&nr_servers);
for (i = 0; i < nr_servers; i++) {
@@ -1374,6 +1383,7 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr)
connman_resolver_append_lifetime(index,
NULL, buf, lifetime);
}
+
} else if (opt->nd_opt_type == 31) { /* ND_OPT_DNSSL */
g_free(domains);
@@ -1499,8 +1509,6 @@ static int process_response(guint32 seq)
static void rtnl_message(void *buf, size_t len)
{
- DBG("buf %p len %zd", buf, len);
-
while (len > 0) {
struct nlmsghdr *hdr = buf;
struct nlmsgerr *err;
diff --git a/src/service.c b/src/service.c
index 033c8f8f..d0543ae5 100755
--- a/src/service.c
+++ b/src/service.c
@@ -112,6 +112,7 @@ struct connman_service {
char **nameservers;
char **nameservers_config;
char **nameservers_auto;
+ int nameservers_timeout;
char **domains;
char *hostname;
char *domainname;
@@ -120,8 +121,13 @@ struct connman_service {
/* 802.1x settings from the config files */
char *eap;
char *identity;
+ char *anonymous_identity;
char *agent_identity;
char *ca_cert_file;
+ char *subject_match;
+ char *altsubject_match;
+ char *domain_suffix_match;
+ char *domain_match;
char *client_cert_file;
char *private_key_file;
char *private_key_passphrase;
@@ -174,7 +180,7 @@ static struct connman_ipconfig *create_ip4config(struct connman_service *service
int index, enum connman_ipconfig_method method);
static struct connman_ipconfig *create_ip6config(struct connman_service *service,
int index);
-
+static void dns_changed(struct connman_service *service);
struct find_data {
const char *path;
@@ -327,9 +333,9 @@ enum connman_service_security __connman_service_string2security(const char *str)
if (!strcmp(str, "psk"))
return CONNMAN_SERVICE_SECURITY_PSK;
- if (!strcmp(str, "ieee8021x"))
+ if (!strcmp(str, "ieee8021x") || !strcmp(str, "8021x"))
return CONNMAN_SERVICE_SECURITY_8021X;
- if (!strcmp(str, "none"))
+ if (!strcmp(str, "none") || !strcmp(str, "open"))
return CONNMAN_SERVICE_SECURITY_NONE;
if (!strcmp(str, "wep"))
return CONNMAN_SERVICE_SECURITY_WEP;
@@ -555,6 +561,19 @@ static bool is_service_owner_user_login(struct connman_service *service)
#endif
}
+static void set_split_routing(struct connman_service *service, bool value)
+{
+ if (service->type != CONNMAN_SERVICE_TYPE_VPN)
+ return;
+
+ service->do_split_routing = value;
+
+ if (service->do_split_routing)
+ service->order = 0;
+ else
+ service->order = 10;
+}
+
int __connman_service_load_modifiable(struct connman_service *service)
{
GKeyFile *keyfile;
@@ -575,8 +594,10 @@ int __connman_service_load_modifiable(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_P2P:
break;
case CONNMAN_SERVICE_TYPE_VPN:
- service->do_split_routing = g_key_file_get_boolean(keyfile,
- service->identifier, "SplitRouting", NULL);
+ set_split_routing(service, g_key_file_get_boolean(keyfile,
+ service->identifier,
+ "SplitRouting", NULL));
+
/* fall through */
case CONNMAN_SERVICE_TYPE_WIFI:
case CONNMAN_SERVICE_TYPE_GADGET:
@@ -648,8 +669,10 @@ static int service_load(struct connman_service *service)
case CONNMAN_SERVICE_TYPE_P2P:
break;
case CONNMAN_SERVICE_TYPE_VPN:
- service->do_split_routing = g_key_file_get_boolean(keyfile,
- service->identifier, "SplitRouting", NULL);
+ set_split_routing(service, g_key_file_get_boolean(keyfile,
+ service->identifier,
+ "SplitRouting", NULL));
+
autoconnect = g_key_file_get_boolean(keyfile,
service->identifier, "AutoConnect", &error);
if (!error)
@@ -1246,15 +1269,12 @@ done:
return result;
}
-static bool is_connecting_state(struct connman_service *service,
- enum connman_service_state state)
+static bool is_connecting(enum connman_service_state state)
{
switch (state) {
case CONNMAN_SERVICE_STATE_UNKNOWN:
case CONNMAN_SERVICE_STATE_IDLE:
case CONNMAN_SERVICE_STATE_FAILURE:
- if (service->network)
- return connman_network_get_connecting(service->network);
case CONNMAN_SERVICE_STATE_DISCONNECT:
case CONNMAN_SERVICE_STATE_READY:
case CONNMAN_SERVICE_STATE_ONLINE:
@@ -1267,8 +1287,7 @@ static bool is_connecting_state(struct connman_service *service,
return false;
}
-static bool is_connected_state(const struct connman_service *service,
- enum connman_service_state state)
+static bool is_connected(enum connman_service_state state)
{
switch (state) {
case CONNMAN_SERVICE_STATE_UNKNOWN:
@@ -1286,57 +1305,127 @@ static bool is_connected_state(const struct connman_service *service,
return false;
}
-static bool is_idle_state(const struct connman_service *service,
- enum connman_service_state state)
+static bool is_idle(enum connman_service_state state)
{
switch (state) {
+ case CONNMAN_SERVICE_STATE_IDLE:
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ return true;
case CONNMAN_SERVICE_STATE_UNKNOWN:
case CONNMAN_SERVICE_STATE_ASSOCIATION:
case CONNMAN_SERVICE_STATE_CONFIGURATION:
case CONNMAN_SERVICE_STATE_READY:
case CONNMAN_SERVICE_STATE_ONLINE:
- case CONNMAN_SERVICE_STATE_DISCONNECT:
- case CONNMAN_SERVICE_STATE_FAILURE:
break;
- case CONNMAN_SERVICE_STATE_IDLE:
- return true;
}
return false;
}
-static bool is_connecting(struct connman_service *service)
+static int nameservers_changed_cb(void *user_data)
{
- return is_connecting_state(service, service->state);
+ struct connman_service *service = user_data;
+
+ DBG("service %p", service);
+
+ service->nameservers_timeout = 0;
+ if ((is_idle(service->state) && !service->nameservers) ||
+ is_connected(service->state))
+ dns_changed(service);
+
+ return FALSE;
}
-static bool is_connected(struct connman_service *service)
+static void nameservers_changed(struct connman_service *service)
{
- return is_connected_state(service, service->state);
+ if (!service->nameservers_timeout)
+ service->nameservers_timeout = g_idle_add(nameservers_changed_cb,
+ service);
}
static bool nameserver_available(struct connman_service *service,
+ enum connman_ipconfig_type type,
const char *ns)
{
int family;
family = connman_inet_check_ipaddress(ns);
- if (family == AF_INET)
- return is_connected_state(service, service->state_ipv4);
+ if (family == AF_INET) {
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ return false;
+
+ return is_connected(service->state_ipv4);
+ }
- if (family == AF_INET6)
- return is_connected_state(service, service->state_ipv6);
+ if (family == AF_INET6) {
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ return false;
+
+ return is_connected(service->state_ipv6);
+ }
return false;
}
+static int searchdomain_add_all(struct connman_service *service)
+{
+ int index, i = 0;
+
+ if (!is_connected(service->state))
+ return -ENOTCONN;
+
+ index = __connman_service_get_index(service);
+ if (index < 0)
+ return -ENXIO;
+
+ if (service->domains) {
+ while (service->domains[i]) {
+ connman_resolver_append(index, service->domains[i],
+ NULL);
+ i++;
+ }
+
+ return 0;
+ }
+
+ if (service->domainname)
+ connman_resolver_append(index, service->domainname, NULL);
+
+ return 0;
+
+}
+
+static int searchdomain_remove_all(struct connman_service *service)
+{
+ int index, i = 0;
+
+ if (!is_connected(service->state))
+ return -ENOTCONN;
+
+ index = __connman_service_get_index(service);
+ if (index < 0)
+ return -ENXIO;
+
+ while (service->domains && service->domains[i]) {
+ connman_resolver_remove(index, service->domains[i], NULL);
+ i++;
+ }
+
+ if (service->domainname)
+ connman_resolver_remove(index, service->domainname, NULL);
+
+ return 0;
+}
+
static int nameserver_add(struct connman_service *service,
+ enum connman_ipconfig_type type,
const char *nameserver)
{
- int index;
+ int index, ret;
- if (!nameserver_available(service, nameserver))
+ if (!nameserver_available(service, type, nameserver))
return 0;
index = __connman_service_get_index(service);
@@ -1346,15 +1435,15 @@ static int nameserver_add(struct connman_service *service,
#if defined TIZEN_EXT
DBG("Resolver append nameserver: %s", nameserver);
#endif
- return connman_resolver_append(index, NULL, nameserver);
+ ret = connman_resolver_append(index, NULL, nameserver);
+ if (ret >= 0)
+ nameservers_changed(service);
+
+ return ret;
}
-#if defined TIZEN_EXT
static int nameserver_add_all(struct connman_service *service,
- enum connman_ipconfig_type type)
-#else
-static int nameserver_add_all(struct connman_service *service)
-#endif
+ enum connman_ipconfig_type type)
{
int i = 0;
@@ -1375,7 +1464,7 @@ static int nameserver_add_all(struct connman_service *service)
service->nameservers_config[i]) == AF_INET &&
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers_config[i]);
}
break;
@@ -1384,7 +1473,7 @@ static int nameserver_add_all(struct connman_service *service)
service->nameservers_config[i]) == AF_INET6 &&
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers_config[i]);
}
break;
@@ -1393,14 +1482,14 @@ static int nameserver_add_all(struct connman_service *service)
service->nameservers_config[i]) == AF_INET &&
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers_config[i]);
}
if (connman_inet_check_ipaddress(
service->nameservers_config[i]) == AF_INET6 &&
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers_config[i]);
}
break;
@@ -1412,19 +1501,12 @@ static int nameserver_add_all(struct connman_service *service)
break;
}
#else
- nameserver_add(service, service->nameservers_config[i]);
+ nameserver_add(service, type,
+ service->nameservers_config[i]);
#endif
i++;
}
-#if !defined TIZEN_EXT
- return 0;
-#endif
- }
-
-#if defined TIZEN_EXT
- i = 0;
-#endif
- if (service->nameservers) {
+ } else if (service->nameservers) {
while (service->nameservers[i]) {
#if defined TIZEN_EXT
DBG("type %d service->nameservers[%d]: %s",type,
@@ -1436,7 +1518,7 @@ static int nameserver_add_all(struct connman_service *service)
service->nameservers[i]) == AF_INET &&
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_DHCP) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers[i]);
}
break;
@@ -1445,7 +1527,7 @@ static int nameserver_add_all(struct connman_service *service)
service->nameservers[i]) == AF_INET6 &&
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_DHCP) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers[i]);
}
break;
@@ -1454,14 +1536,14 @@ static int nameserver_add_all(struct connman_service *service)
service->nameservers[i]) == AF_INET &&
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_DHCP) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers[i]);
}
if (connman_inet_check_ipaddress(
service->nameservers[i]) == AF_INET6 &&
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_DHCP) {
- nameserver_add(service,
+ nameserver_add(service, type,
service->nameservers[i]);
}
break;
@@ -1473,21 +1555,28 @@ static int nameserver_add_all(struct connman_service *service)
break;
}
#else
- nameserver_add(service, service->nameservers[i]);
+ nameserver_add(service, type,
+ service->nameservers[i]);
#endif
i++;
}
}
+ if (!i)
+ __connman_resolver_append_fallback_nameservers();
+
+ searchdomain_add_all(service);
+
return 0;
}
static int nameserver_remove(struct connman_service *service,
+ enum connman_ipconfig_type type,
const char *nameserver)
{
- int index;
+ int index, ret;
- if (!nameserver_available(service, nameserver))
+ if (!nameserver_available(service, type, nameserver))
return 0;
index = __connman_service_get_index(service);
@@ -1497,15 +1586,15 @@ static int nameserver_remove(struct connman_service *service,
#if defined TIZEN_EXT
DBG("Resolver remove nameserver: %s", nameserver);
#endif
- return connman_resolver_remove(index, NULL, nameserver);
+ ret = connman_resolver_remove(index, NULL, nameserver);
+ if (ret >= 0)
+ nameservers_changed(service);
+
+ return ret;
}
-#if defined TIZEN_EXT
static int nameserver_remove_all(struct connman_service *service,
- enum connman_ipconfig_type type)
-#else
-static int nameserver_remove_all(struct connman_service *service)
-#endif
+ enum connman_ipconfig_type type)
{
#if defined TIZEN_EXT
/**
@@ -1534,7 +1623,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_DHCP ||
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers_config[i]);
}
break;
@@ -1545,7 +1634,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_DHCP ||
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers_config[i]);
}
break;
@@ -1556,7 +1645,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_DHCP ||
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers_config[i]);
}
if (connman_inet_check_ipaddress(
@@ -1565,7 +1654,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_DHCP ||
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers_config[i]);
}
break;
@@ -1577,7 +1666,8 @@ static int nameserver_remove_all(struct connman_service *service)
break;
}
#else
- nameserver_remove(service, service->nameservers_config[i]);
+ nameserver_remove(service, type,
+ service->nameservers_config[i]);
#endif
i++;
}
@@ -1595,7 +1685,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_MANUAL ||
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_DHCP)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers[i]);
}
break;
@@ -1606,7 +1696,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_MANUAL ||
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_DHCP)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers[i]);
}
break;
@@ -1617,7 +1707,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_MANUAL ||
service->dns_config_method_ipv4 ==
CONNMAN_DNSCONFIG_METHOD_DHCP)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers[i]);
}
if (connman_inet_check_ipaddress(
@@ -1626,7 +1716,7 @@ static int nameserver_remove_all(struct connman_service *service)
CONNMAN_DNSCONFIG_METHOD_MANUAL ||
service->dns_config_method_ipv6 ==
CONNMAN_DNSCONFIG_METHOD_DHCP)) {
- nameserver_remove(service,
+ nameserver_remove(service, type,
service->nameservers[i]);
}
break;
@@ -1638,60 +1728,12 @@ static int nameserver_remove_all(struct connman_service *service)
break;
}
#else
- nameserver_remove(service, service->nameservers[i]);
+ nameserver_remove(service, type, service->nameservers[i]);
#endif
i++;
}
- return 0;
-}
-
-static int searchdomain_add_all(struct connman_service *service)
-{
- int index, i = 0;
-
- if (!is_connected(service))
- return -ENOTCONN;
-
- index = __connman_service_get_index(service);
- if (index < 0)
- return -ENXIO;
-
- if (service->domains) {
- while (service->domains[i]) {
- connman_resolver_append(index, service->domains[i],
- NULL);
- i++;
- }
-
- return 0;
- }
-
- if (service->domainname)
- connman_resolver_append(index, service->domainname, NULL);
-
- return 0;
-
-}
-
-static int searchdomain_remove_all(struct connman_service *service)
-{
- int index, i = 0;
-
- if (!is_connected(service))
- return -ENOTCONN;
-
- index = __connman_service_get_index(service);
- if (index < 0)
- return -ENXIO;
-
- while (service->domains && service->domains[i]) {
- connman_resolver_remove(index, service->domains[i], NULL);
- i++;
- }
-
- if (service->domainname)
- connman_resolver_remove(index, service->domainname, NULL);
+ searchdomain_remove_all(service);
return 0;
}
@@ -1750,13 +1792,11 @@ int __connman_service_nameserver_append(struct connman_service *service,
#ifdef TIZEN_EXT
if(type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
- service->dns_config_method_ipv4 ==
- CONNMAN_DNSCONFIG_METHOD_UNKNOWN)
+ service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_UNKNOWN)
service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP;
if(type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
- service->dns_config_method_ipv6 ==
- CONNMAN_DNSCONFIG_METHOD_UNKNOWN)
+ service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_UNKNOWN)
service->dns_config_method_ipv6 = CONNMAN_DNSCONFIG_METHOD_DHCP;
#endif
@@ -1764,12 +1804,13 @@ int __connman_service_nameserver_append(struct connman_service *service,
service->nameservers_auto = nameservers;
} else {
service->nameservers = nameservers;
-#if defined TIZEN_EXT
- DBG("nameserver add: %s, type: %d", nameserver, type);
-#endif
- nameserver_add(service, nameserver);
+ nameserver_add(service, CONNMAN_IPCONFIG_TYPE_ALL, nameserver);
}
+ nameservers_changed(service);
+
+ searchdomain_add_all(service);
+
return 0;
}
@@ -1799,7 +1840,7 @@ int __connman_service_nameserver_remove(struct connman_service *service,
if (!nameservers)
return 0;
- for (i = 0; nameservers && nameservers[i]; i++)
+ for (i = 0; nameservers[i]; i++)
if (g_strcmp0(nameservers[i], nameserver) == 0) {
found = true;
break;
@@ -1840,8 +1881,12 @@ set_servers:
service->nameservers = nameservers;
#if defined TIZEN_EXT
DBG("nameserver remove ip_type: %d", type);
+ nameserver_remove(service, type,
+ nameserver);
+#else
+ nameserver_remove(service, CONNMAN_IPCONFIG_TYPE_ALL,
+ nameserver);
#endif
- nameserver_remove(service, nameserver);
}
return 0;
@@ -1849,23 +1894,12 @@ set_servers:
void __connman_service_nameserver_clear(struct connman_service *service)
{
-#if defined TIZEN_EXT
- DBG("nameserver remove all ip_type: CONNMAN_IPCONFIG_TYPE_ALL");
nameserver_remove_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
-#else
- nameserver_remove_all(service);
-#endif
g_strfreev(service->nameservers);
service->nameservers = NULL;
-#if defined TIZEN_EXT
- DBG("nameserver add all ip_type: CONNMAN_IPCONFIG_TYPE_ALL");
nameserver_add_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
-#else
- nameserver_add_all(service);
-#endif
-
}
static void add_nameserver_route(int family, int index, char *nameserver,
@@ -1978,6 +2012,18 @@ void __connman_service_nameserver_del_routes(struct connman_service *service,
nameserver_del_routes(index, service->nameservers, type);
}
+static void address_updated(struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ if (is_connected(service->state) &&
+ service == __connman_service_get_default()) {
+ nameserver_remove_all(service, type);
+ nameserver_add_all(service, type);
+
+ __connman_timeserver_sync(service);
+ }
+}
+
static struct connman_stats *stats_get(struct connman_service *service)
{
if (service->roaming)
@@ -2107,21 +2153,21 @@ struct connman_service *connman_service_get_default_connection(void)
__connman_service_type2string(service->type));
if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
- is_connected(service) == TRUE) {
+ is_connected(service->state) == TRUE) {
return service;
} else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
__connman_service_is_internet_profile(service) == TRUE) {
if (default_service == NULL)
default_service = service;
- else if (is_connected(service) == TRUE &&
- is_connected(default_service) == FALSE)
+ else if (is_connected(service->state) == TRUE &&
+ is_connected(default_service->state) == FALSE)
default_service = service;
} else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET &&
- is_connected(service) == TRUE) {
+ is_connected(service->state) == TRUE) {
if (default_service == NULL)
default_service = service;
} else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH &&
- is_connected(service) == TRUE) {
+ is_connected(service->state) == TRUE) {
if (default_service == NULL)
default_service = service;
}
@@ -2140,7 +2186,7 @@ struct connman_service *__connman_service_get_default(void)
service = service_list->data;
- if (!is_connected(service))
+ if (!is_connected(service->state))
return NULL;
return service;
@@ -2339,7 +2385,7 @@ static void append_ipv4(DBusMessageIter *iter, void *user_data)
{
struct connman_service *service = user_data;
- if (!is_connected_state(service, service->state_ipv4))
+ if (!is_connected(service->state_ipv4))
return;
if (service->ipconfig_ipv4)
@@ -2350,7 +2396,7 @@ static void append_ipv6(DBusMessageIter *iter, void *user_data)
{
struct connman_service *service = user_data;
- if (!is_connected_state(service, service->state_ipv6))
+ if (!is_connected(service->state_ipv6))
return;
if (service->ipconfig_ipv6)
@@ -2384,9 +2430,9 @@ static void append_nameservers(DBusMessageIter *iter,
for (i = 0; servers[i]; i++) {
if (service)
- available = nameserver_available(service, servers[i]);
-
- DBG("servers[%d] %s available %d", i, servers[i], available);
+ available = nameserver_available(service,
+ CONNMAN_IPCONFIG_TYPE_ALL,
+ servers[i]);
if (available)
dbus_message_iter_append_basic(iter,
@@ -2401,7 +2447,8 @@ static void append_nameserver_manual(DBusMessageIter *iter,
bool available = true;
if (service)
- available = nameserver_available(service, server);
+ available = nameserver_available(service,
+ CONNMAN_IPCONFIG_TYPE_ALL, server);
if (available)
dbus_message_iter_append_basic(iter,
@@ -2414,7 +2461,8 @@ static void append_nameserver_dhcp(DBusMessageIter *iter,
bool available = true;
if (service)
- available = nameserver_available(service, server);
+ available = nameserver_available(service,
+ CONNMAN_IPCONFIG_TYPE_ALL, server);
if (available)
dbus_message_iter_append_basic(iter,
@@ -2429,7 +2477,7 @@ static void append_dns(DBusMessageIter *iter, void *user_data)
int i;
#endif
- if (!is_connected(service))
+ if (!is_connected(service->state))
return;
#ifdef TIZEN_EXT
@@ -2639,8 +2687,8 @@ static void append_domain(DBusMessageIter *iter, void *user_data)
{
struct connman_service *service = user_data;
- if (!is_connected(service) &&
- !is_connecting(service))
+ if (!is_connected(service->state) &&
+ !is_connecting(service->state))
return;
if (service->domains)
@@ -2684,7 +2732,7 @@ static void append_proxy(DBusMessageIter *iter, void *user_data)
const char *method = proxymethod2string(
CONNMAN_SERVICE_PROXY_METHOD_DIRECT);
- if (!is_connected(service))
+ if (!is_connected(service->state))
return;
proxy = connman_service_get_proxy_method(service);
@@ -2771,7 +2819,7 @@ static void append_provider(DBusMessageIter *iter, void *user_data)
{
struct connman_service *service = user_data;
- if (!is_connected(service))
+ if (!is_connected(service->state))
return;
if (service->provider)
@@ -2784,11 +2832,13 @@ static void settings_changed(struct connman_service *service,
{
enum connman_ipconfig_type type;
+ type = __connman_ipconfig_get_config_type(ipconfig);
+
+ __connman_notifier_ipconfig_changed(service, ipconfig);
+
if (!allow_property_changed(service))
return;
- type = __connman_ipconfig_get_config_type(ipconfig);
-
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE, "IPv4",
@@ -2797,8 +2847,6 @@ static void settings_changed(struct connman_service *service,
connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE, "IPv6",
append_ipv6, service);
-
- __connman_notifier_ipconfig_changed(service, ipconfig);
}
static void ipv4_configuration_changed(struct connman_service *service)
@@ -2813,6 +2861,15 @@ static void ipv4_configuration_changed(struct connman_service *service)
service);
}
+void __connman_service_notify_ipv4_configuration(
+ struct connman_service *service)
+{
+ if (!service)
+ return;
+
+ ipv4_configuration_changed(service);
+}
+
static void ipv6_configuration_changed(struct connman_service *service)
{
if (!allow_property_changed(service))
@@ -3074,7 +3131,7 @@ void __connman_service_notify(struct connman_service *service,
if (!service)
return;
- if (!is_connected(service))
+ if (!is_connected(service->state))
return;
stats_update(service,
@@ -3248,25 +3305,14 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
connman_dbus_dict_append_basic(dict, "Frequency",
DBUS_TYPE_UINT16, &frequency);
}
-
- unsigned char *wifi_vsie;
+ const void *wifi_vsie;
unsigned int wifi_vsie_len;
- GSList *vsie_list = NULL;
-
- if (service->network)
- vsie_list = (GSList *)connman_network_get_vsie_list(service->network);
-
- if (vsie_list) {
- DBG("ConnMan, service->path=%s No.of elements in list: %d", service->path, g_slist_length(vsie_list));
- GSList *list;
- for (list = vsie_list; list; list = list->next) {
- wifi_vsie = (unsigned char *)list->data;
- wifi_vsie_len = wifi_vsie[1] + 2;
-
- connman_dbus_dict_append_fixed_array(dict, "Vsie", DBUS_TYPE_BYTE,
- &wifi_vsie, wifi_vsie_len);
- }
+ wifi_vsie = connman_network_get_blob(service->network, "WiFi.Vsie", &wifi_vsie_len);
+ if(wifi_vsie_len > 0) {
+ DBG("ConnMan, service->path=%s vsie length=%d", service->path, wifi_vsie_len);
}
+ connman_dbus_dict_append_fixed_array(dict, "Vsie", DBUS_TYPE_BYTE,
+ &wifi_vsie, wifi_vsie_len);
#endif
str = __connman_service_type2string(service->type);
@@ -3886,6 +3932,81 @@ void __connman_service_set_identity(struct connman_service *service,
service->identity);
}
+void __connman_service_set_anonymous_identity(struct connman_service *service,
+ const char *anonymous_identity)
+{
+ if (service->immutable || service->hidden)
+ return;
+
+ g_free(service->anonymous_identity);
+ service->anonymous_identity = g_strdup(anonymous_identity);
+
+ if (service->network)
+ connman_network_set_string(service->network,
+ "WiFi.AnonymousIdentity",
+ service->anonymous_identity);
+}
+
+void __connman_service_set_subject_match(struct connman_service *service,
+ const char *subject_match)
+{
+ if (service->immutable || service->hidden)
+ return;
+
+ g_free(service->subject_match);
+ service->subject_match = g_strdup(subject_match);
+
+ if (service->network)
+ connman_network_set_string(service->network,
+ "WiFi.SubjectMatch",
+ service->subject_match);
+}
+
+void __connman_service_set_altsubject_match(struct connman_service *service,
+ const char *altsubject_match)
+{
+ if (service->immutable || service->hidden)
+ return;
+
+ g_free(service->altsubject_match);
+ service->altsubject_match = g_strdup(altsubject_match);
+
+ if (service->network)
+ connman_network_set_string(service->network,
+ "WiFi.AltSubjectMatch",
+ service->altsubject_match);
+}
+
+void __connman_service_set_domain_suffix_match(struct connman_service *service,
+ const char *domain_suffix_match)
+{
+ if (service->immutable || service->hidden)
+ return;
+
+ g_free(service->domain_suffix_match);
+ service->domain_suffix_match = g_strdup(domain_suffix_match);
+
+ if (service->network)
+ connman_network_set_string(service->network,
+ "WiFi.DomainSuffixMatch",
+ service->domain_suffix_match);
+}
+
+void __connman_service_set_domain_match(struct connman_service *service,
+ const char *domain_match)
+{
+ if (service->immutable || service->hidden)
+ return;
+
+ g_free(service->domain_match);
+ service->domain_match = g_strdup(domain_match);
+
+ if (service->network)
+ connman_network_set_string(service->network,
+ "WiFi.DomainMatch",
+ service->domain_match);
+}
+
void __connman_service_set_agent_identity(struct connman_service *service,
const char *agent_identity)
{
@@ -3900,7 +4021,7 @@ void __connman_service_set_agent_identity(struct connman_service *service,
service->agent_identity);
}
-static int check_passphrase(enum connman_service_security security,
+int __connman_service_check_passphrase(enum connman_service_security security,
const char *passphrase)
{
guint i;
@@ -3979,7 +4100,7 @@ int __connman_service_set_passphrase(struct connman_service *service,
service->security != CONNMAN_SERVICE_SECURITY_RSN &&
service->security != CONNMAN_SERVICE_SECURITY_WEP)
#endif
- err = check_passphrase(service->security, passphrase);
+ err = __connman_service_check_passphrase(service->security, passphrase);
if (err < 0)
return err;
@@ -4009,8 +4130,6 @@ static DBusMessage *get_properties(DBusConnection *conn,
DBusMessage *reply;
DBusMessageIter array, dict;
- DBG("service %p", service);
-
reply = dbus_message_new_method_return(msg);
if (!reply)
return NULL;
@@ -4024,6 +4143,23 @@ static DBusMessage *get_properties(DBusConnection *conn,
return reply;
}
+static char **remove_empty_strings(char **strv)
+{
+ int index = 0;
+ char **iter = strv;
+
+ while (*iter) {
+ if (**iter)
+ strv[index++] = *iter;
+ else
+ g_free(*iter);
+ iter++;
+ }
+
+ strv[index] = NULL;
+ return strv;
+}
+
static int update_proxy_configuration(struct connman_service *service,
DBusMessageIter *array)
{
@@ -4137,20 +4273,24 @@ static int update_proxy_configuration(struct connman_service *service,
if (servers_str) {
g_strfreev(service->proxies);
- if (servers_str->len > 0)
- service->proxies = g_strsplit_set(
+ if (servers_str->len > 0) {
+ char **proxies = g_strsplit_set(
servers_str->str, " ", 0);
- else
+ proxies = remove_empty_strings(proxies);
+ service->proxies = proxies;
+ } else
service->proxies = NULL;
}
if (excludes_str) {
g_strfreev(service->excludes);
- if (excludes_str->len > 0)
- service->excludes = g_strsplit_set(
+ if (excludes_str->len > 0) {
+ char **excludes = g_strsplit_set(
excludes_str->str, " ", 0);
- else
+ excludes = remove_empty_strings(excludes);
+ service->excludes = excludes;
+ } else
service->excludes = NULL;
}
@@ -4162,7 +4302,7 @@ static int update_proxy_configuration(struct connman_service *service,
g_free(service->pac);
if (url && strlen(url) > 0)
- service->pac = g_strdup(url);
+ service->pac = g_strstrip(g_strdup(url));
else
service->pac = NULL;
@@ -4239,8 +4379,7 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
new_method = __connman_ipconfig_get_method(new_ipconfig);
}
- if (is_connecting_state(service, state) ||
- is_connected_state(service, state))
+ if (is_connecting(state) || is_connected(state))
__connman_network_clear_ipconfig(service->network, ipconfig);
__connman_ipconfig_unref(ipconfig);
@@ -4250,8 +4389,7 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
service->ipconfig_ipv6 = new_ipconfig;
- if (is_connecting_state(service, state) ||
- is_connected_state(service, state))
+ if (is_connecting(state) || is_connected(state))
__connman_ipconfig_enable(new_ipconfig);
if (new_state && new_method != old_method) {
@@ -4260,6 +4398,9 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
else
*new_state = service->state_ipv6;
+ settings_changed(service, new_ipconfig);
+ address_updated(service, new_method);
+
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
}
@@ -4286,7 +4427,7 @@ static DBusMessage *set_property(DBusConnection *conn,
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __connman_error_invalid_arguments(msg);
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI && is_connected(service)) {
+ if (service->type == CONNMAN_SERVICE_TYPE_WIFI && is_connected(service->state)) {
uid_t uid;
if (connman_dbus_get_connection_unix_user_sync(conn,
dbus_message_get_sender(msg),
@@ -4358,10 +4499,11 @@ static DBusMessage *set_property(DBusConnection *conn,
gw = __connman_ipconfig_get_gateway_from_index(index,
CONNMAN_IPCONFIG_TYPE_ALL);
+#if !defined TIZEN_EXT
if (gw && strlen(gw))
__connman_service_nameserver_del_routes(service,
CONNMAN_IPCONFIG_TYPE_ALL);
-
+#endif
dbus_message_iter_recurse(&value, &entry);
#if defined TIZEN_EXT
@@ -4415,12 +4557,13 @@ static DBusMessage *set_property(DBusConnection *conn,
continue;
}
#endif
- if (connman_inet_check_ipaddress(val) > 0) {
- if (str->len > 0)
- g_string_append_printf(str, " %s", val);
- else
- g_string_append(str, val);
- }
+ if (!val[0])
+ continue;
+
+ if (str->len > 0)
+ g_string_append_printf(str, " %s", val);
+ else
+ g_string_append(str, val);
}
#if defined TIZEN_EXT
@@ -4436,13 +4579,21 @@ static DBusMessage *set_property(DBusConnection *conn,
DBG("%s ip_type: %d nameserver remove all", name, ip_type);
nameserver_remove_all(service, ip_type);
#else
- nameserver_remove_all(service);
+ nameserver_remove_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
#endif
g_strfreev(service->nameservers_config);
if (str->len > 0) {
- service->nameservers_config =
- g_strsplit_set(str->str, " ", 0);
+ char **nameservers, **iter;
+
+ nameservers = g_strsplit_set(str->str, " ", 0);
+
+ for (iter = nameservers; *iter; iter++)
+ if (connman_inet_check_ipaddress(*iter) <= 0)
+ *iter[0] = '\0';
+
+ nameservers = remove_empty_strings(nameservers);
+ service->nameservers_config = nameservers;
} else {
service->nameservers_config = NULL;
}
@@ -4456,7 +4607,7 @@ static DBusMessage *set_property(DBusConnection *conn,
DBG("%s ip_type: %d nameserver add all", name, ip_type);
nameserver_add_all(service, ip_type);
#else
- nameserver_add_all(service);
+ nameserver_add_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
#endif
dns_configuration_changed(service);
@@ -4473,8 +4624,7 @@ static DBusMessage *set_property(DBusConnection *conn,
service_save(service);
} else if (g_str_equal(name, "Timeservers.Configuration")) {
DBusMessageIter entry;
- GSList *list = NULL;
- int count = 0;
+ GString *str;
if (service->immutable)
return __connman_error_not_supported(msg);
@@ -4482,35 +4632,37 @@ static DBusMessage *set_property(DBusConnection *conn,
if (type != DBUS_TYPE_ARRAY)
return __connman_error_invalid_arguments(msg);
+ str = g_string_new(NULL);
+ if (!str)
+ return __connman_error_invalid_arguments(msg);
+
dbus_message_iter_recurse(&value, &entry);
while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
const char *val;
- GSList *new_head;
-
dbus_message_iter_get_basic(&entry, &val);
+ dbus_message_iter_next(&entry);
- new_head = __connman_timeserver_add_list(list, val);
- if (list != new_head) {
- count++;
- list = new_head;
- }
+ if (!val[0])
+ continue;
- dbus_message_iter_next(&entry);
+ if (str->len > 0)
+ g_string_append_printf(str, " %s", val);
+ else
+ g_string_append(str, val);
}
g_strfreev(service->timeservers_config);
service->timeservers_config = NULL;
- if (list) {
- service->timeservers_config = g_new0(char *, count+1);
+ if (str->len > 0) {
+ char **timeservers = g_strsplit_set(str->str, " ", 0);
+ timeservers = remove_empty_strings(timeservers);
+ service->timeservers_config = timeservers;
+ } else
+ service->timeservers = NULL;
- while (list) {
- count--;
- service->timeservers_config[count] = list->data;
- list = g_slist_delete_link(list, list);
- };
- }
+ g_string_free(str, TRUE);
service_save(service);
timeservers_configuration_changed(service);
@@ -4538,6 +4690,10 @@ static DBusMessage *set_property(DBusConnection *conn,
const char *val;
dbus_message_iter_get_basic(&entry, &val);
dbus_message_iter_next(&entry);
+
+ if (!val[0])
+ continue;
+
if (str->len > 0)
g_string_append_printf(str, " %s", val);
else
@@ -4547,9 +4703,11 @@ static DBusMessage *set_property(DBusConnection *conn,
searchdomain_remove_all(service);
g_strfreev(service->domains);
- if (str->len > 0)
- service->domains = g_strsplit_set(str->str, " ", 0);
- else
+ if (str->len > 0) {
+ char **domains = g_strsplit_set(str->str, " ", 0);
+ domains = remove_empty_strings(domains);
+ service->domains = domains;
+ } else
service->domains = NULL;
g_string_free(str, TRUE);
@@ -4606,8 +4764,7 @@ static DBusMessage *set_property(DBusConnection *conn,
&state);
if (err < 0) {
- if (is_connected_state(service, state) ||
- is_connecting_state(service, state)) {
+ if (is_connected(state) || is_connecting(state)) {
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
__connman_network_enable_ipconfig(service->network,
service->ipconfig_ipv4);
@@ -4624,7 +4781,8 @@ static DBusMessage *set_property(DBusConnection *conn,
else
ipv6_configuration_changed(service);
- if (is_connecting(service) || is_connected(service)) {
+ if (is_connecting(service->state) ||
+ is_connected(service->state)) {
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
__connman_network_enable_ipconfig(service->network,
service->ipconfig_ipv4);
@@ -4668,6 +4826,41 @@ static void set_error(struct connman_service *service,
DBUS_TYPE_STRING, &str);
}
+static void remove_timeout(struct connman_service *service)
+{
+ if (service->timeout > 0) {
+ g_source_remove(service->timeout);
+ service->timeout = 0;
+ }
+}
+
+static void reply_pending(struct connman_service *service, int error)
+{
+ remove_timeout(service);
+
+ if (service->pending) {
+ connman_dbus_reply_pending(service->pending, error, NULL);
+ service->pending = NULL;
+ }
+
+ if (service->provider_pending) {
+ connman_dbus_reply_pending(service->provider_pending,
+ error, service->path);
+ service->provider_pending = NULL;
+ }
+}
+
+static void service_complete(struct connman_service *service)
+{
+ reply_pending(service, EIO);
+
+ if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
+ __connman_service_auto_connect(service->connect_reason);
+
+ g_get_current_time(&service->modified);
+ service_save(service);
+}
+
static void set_idle(struct connman_service *service)
{
service->state = service->state_ipv4 = service->state_ipv6 =
@@ -4690,8 +4883,8 @@ static DBusMessage *clear_property(DBusConnection *conn,
if (g_str_equal(name, "Error")) {
set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
- g_get_current_time(&service->modified);
- service_save(service);
+ __connman_service_clear_error(service);
+ service_complete(service);
} else
return __connman_error_invalid_property(msg);
@@ -4746,6 +4939,7 @@ static void disconnect_on_last_session(enum connman_service_type type)
}
static int active_sessions[MAX_CONNMAN_SERVICE_TYPES] = {};
+static int always_connect[MAX_CONNMAN_SERVICE_TYPES] = {};
static int active_count = 0;
void __connman_service_set_active_session(bool enable, GSList *list)
@@ -4758,7 +4952,7 @@ void __connman_service_set_active_session(bool enable, GSList *list)
else
active_count--;
- while (list != NULL) {
+ while (list) {
enum connman_service_type type = GPOINTER_TO_INT(list->data);
switch (type) {
@@ -4830,7 +5024,7 @@ static GList *preferred_tech_list_get(void)
for (list = service_list; list; list = list->next) {
struct connman_service *service = list->data;
- if (!is_connected(service))
+ if (!is_connected(service->state))
break;
if (service->connect_reason ==
@@ -4862,6 +5056,43 @@ static GList *preferred_tech_list_get(void)
return tech_data.preferred_list;
}
+static void set_always_connecting_technologies()
+{
+ unsigned int *always_connected_techs =
+ connman_setting_get_uint_list("AlwaysConnectedTechnologies");
+ int i;
+ for (i = 0; always_connected_techs && always_connected_techs[i]; i++)
+ always_connect[always_connected_techs[i]] = 1;
+}
+
+static bool autoconnect_no_session_active(struct connman_service *service)
+{
+ /*
+ * Test active_count to see if there are no sessions set up and
+ * stop autoconnecting, but continue connecting if the service
+ * belongs to a technology which should always autoconnect.
+ */
+ if (!active_count && !always_connect[service->type])
+ return true;
+
+ return false;
+}
+
+static bool autoconnect_already_connecting(struct connman_service *service,
+ bool autoconnecting)
+{
+ /*
+ * If another service is already connecting and this service type has
+ * not been marked as always connecting, stop the connecting procedure.
+ */
+ if (autoconnecting &&
+ !active_sessions[service->type] &&
+ !always_connect[service->type])
+ return true;
+
+ return false;
+}
+
static bool auto_connect_service(GList *services,
enum connman_service_connect_reason reason,
bool preferred)
@@ -4895,15 +5126,15 @@ static bool auto_connect_service(GList *services,
/* Tizen takes Wi-Fi as the highest priority into consideration. */
if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
- if (is_connecting(service) == TRUE || is_connected(service) == TRUE)
+ if (is_connecting(service->state) == TRUE || is_connected(service->state) == TRUE)
continue;
#endif
if (service->pending ||
- is_connecting(service) ||
- is_connected(service)) {
- if (!active_count)
- return true;
+ is_connecting(service->state) ||
+ is_connected(service->state)) {
+ if (autoconnect_no_session_active(service))
+ return true;
ignore[service->type] = true;
autoconnecting = true;
@@ -4937,7 +5168,7 @@ static bool auto_connect_service(GList *services,
CONNMAN_SERVICE_STATE_IDLE)
continue;
- if (autoconnecting && !active_sessions[service->type]) {
+ if (autoconnect_already_connecting(service, autoconnecting)) {
DBG("service %p type %s has no users", service,
__connman_service_type2string(service->type));
continue;
@@ -4953,7 +5184,7 @@ static bool auto_connect_service(GList *services,
__connman_service_connect(service, reason);
- if (!active_count)
+ if (autoconnect_no_session_active(service))
return true;
ignore[service->type] = true;
@@ -5032,7 +5263,7 @@ void __connman_service_auto_connect(enum connman_service_connect_reason reason)
* is ignored as its last state was FAILURE rather than IDLE */
autoconnect_timeout = g_timeout_add(500, run_auto_connect,
#else
- autoconnect_timeout = g_timeout_add_seconds(0, run_auto_connect,
+ autoconnect_timeout = g_idle_add(run_auto_connect,
#endif
GUINT_TO_POINTER(reason));
}
@@ -5050,7 +5281,8 @@ static gboolean run_vpn_auto_connect(gpointer data) {
if (service->type != CONNMAN_SERVICE_TYPE_VPN)
continue;
- if (is_connected(service) || is_connecting(service)) {
+ if (is_connected(service->state) ||
+ is_connecting(service->state)) {
if (!service->do_split_routing)
need_split = true;
continue;
@@ -5086,31 +5318,7 @@ static void vpn_auto_connect(void)
return;
vpn_autoconnect_timeout =
- g_timeout_add_seconds(0, run_vpn_auto_connect, NULL);
-}
-
-static void remove_timeout(struct connman_service *service)
-{
- if (service->timeout > 0) {
- g_source_remove(service->timeout);
- service->timeout = 0;
- }
-}
-
-static void reply_pending(struct connman_service *service, int error)
-{
- remove_timeout(service);
-
- if (service->pending) {
- connman_dbus_reply_pending(service->pending, error, NULL);
- service->pending = NULL;
- }
-
- if (service->provider_pending) {
- connman_dbus_reply_pending(service->provider_pending,
- error, service->path);
- service->provider_pending = NULL;
- }
+ g_idle_add(run_vpn_auto_connect, NULL);
}
bool
@@ -5187,9 +5395,6 @@ static gboolean connect_timeout(gpointer user_data)
else if (service->provider)
connman_provider_disconnect(service->provider);
- __connman_ipconfig_disable(service->ipconfig_ipv4);
- __connman_ipconfig_disable(service->ipconfig_ipv6);
-
__connman_stats_service_unregister(service);
if (service->pending) {
@@ -5284,7 +5489,7 @@ static DBusMessage *connect_service(DBusConnection *conn,
if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
break;
#endif
- if (!is_connecting(temp) && !is_connected(temp))
+ if (!is_connecting(temp->state) && !is_connected(temp->state))
break;
if (service == temp)
@@ -5339,7 +5544,7 @@ static DBusMessage *disconnect_service(DBusConnection *conn,
if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
return __connman_error_failed(msg, EISCONN);
- if (is_connected(service) == TRUE &&
+ if (is_connected(service->state) == TRUE &&
service == connman_service_get_default_connection())
return __connman_error_failed(msg, EISCONN);
}
@@ -5398,8 +5603,7 @@ bool __connman_service_remove(struct connman_service *service)
return false;
#if !defined TIZEN_EXT
- if (!service->favorite && service->state !=
- CONNMAN_SERVICE_STATE_FAILURE)
+ if (!service->favorite && !is_idle(service->state))
return false;
#endif
@@ -5411,6 +5615,21 @@ bool __connman_service_remove(struct connman_service *service)
g_free(service->identity);
service->identity = NULL;
+ g_free(service->anonymous_identity);
+ service->anonymous_identity = NULL;
+
+ g_free(service->subject_match);
+ service->subject_match = NULL;
+
+ g_free(service->altsubject_match);
+ service->altsubject_match = NULL;
+
+ g_free(service->domain_suffix_match);
+ service->domain_suffix_match = NULL;
+
+ g_free(service->domain_match);
+ service->domain_match = NULL;
+
g_free(service->agent_identity);
service->agent_identity = NULL;
@@ -5613,11 +5832,11 @@ static DBusMessage *move_service(DBusConnection *conn,
return __connman_error_invalid_service(msg);
}
- target->do_split_routing = true;
+ set_split_routing(target, true);
} else
- target->do_split_routing = false;
+ set_split_routing(target, false);
- service->do_split_routing = false;
+ set_split_routing(service, false);
target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
@@ -5855,10 +6074,8 @@ static bool allow_property_changed(struct connman_service *service)
return FALSE;
#endif
if (g_hash_table_lookup_extended(services_notify->add, service->path,
- NULL, NULL)) {
- DBG("no property updates for service %p", service);
+ NULL, NULL))
return false;
- }
return true;
}
@@ -5906,6 +6123,11 @@ static void service_free(gpointer user_data)
reply_pending(service, ENOENT);
+ if (service->nameservers_timeout) {
+ g_source_remove(service->nameservers_timeout);
+ dns_changed(service);
+ }
+
__connman_notifier_service_remove(service);
service_schedule_removed(service);
@@ -5964,8 +6186,13 @@ static void service_free(gpointer user_data)
g_free(service->identifier);
g_free(service->eap);
g_free(service->identity);
+ g_free(service->anonymous_identity);
g_free(service->agent_identity);
g_free(service->ca_cert_file);
+ g_free(service->subject_match);
+ g_free(service->altsubject_match);
+ g_free(service->domain_suffix_match);
+ g_free(service->domain_match);
g_free(service->client_cert_file);
g_free(service->private_key_file);
g_free(service->private_key_passphrase);
@@ -6138,8 +6365,8 @@ static gint service_compare(gconstpointer a, gconstpointer b)
state_a = service_a->state;
state_b = service_b->state;
- a_connected = is_connected(service_a);
- b_connected = is_connected(service_b);
+ a_connected = is_connected(state_a);
+ b_connected = is_connected(state_b);
if (a_connected && b_connected) {
if (service_a->order > service_b->order)
@@ -6164,9 +6391,9 @@ static gint service_compare(gconstpointer a, gconstpointer b)
if (b_connected)
return 1;
- if (is_connecting(service_a))
+ if (is_connecting(state_a))
return -1;
- if (is_connecting(service_b))
+ if (is_connecting(state_b))
return 1;
}
@@ -6177,6 +6404,20 @@ static gint service_compare(gconstpointer a, gconstpointer b)
return 1;
if (service_a->type != service_b->type) {
+ unsigned int *tech_array;
+ int i;
+
+ tech_array = connman_setting_get_uint_list(
+ "PreferredTechnologies");
+ if (tech_array) {
+ for (i = 0; tech_array[i]; i++) {
+ if (tech_array[i] == service_a->type)
+ return -1;
+
+ if (tech_array[i] == service_b->type)
+ return 1;
+ }
+ }
if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
return -1;
@@ -6224,6 +6465,12 @@ static void service_list_sort(void)
}
}
+int __connman_service_compare(const struct connman_service *a,
+ const struct connman_service *b)
+{
+ return service_compare(a, b);
+}
+
/**
* connman_service_get_type:
* @service: service structure
@@ -6275,7 +6522,7 @@ bool __connman_service_is_user_allowed(enum connman_service_type type,
if (service->type != type)
continue;
- if (is_connected(service)) {
+ if (is_connected(service->state)) {
owner_user = service->user.favorite_user;
break;
}
@@ -6345,14 +6592,12 @@ bool __connman_service_is_connected_state(struct connman_service *service,
case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
break;
case CONNMAN_IPCONFIG_TYPE_IPV4:
- return is_connected_state(service, service->state_ipv4);
+ return is_connected(service->state_ipv4);
case CONNMAN_IPCONFIG_TYPE_IPV6:
- return is_connected_state(service, service->state_ipv6);
+ return is_connected(service->state_ipv6);
case CONNMAN_IPCONFIG_TYPE_ALL:
- return is_connected_state(service,
- CONNMAN_IPCONFIG_TYPE_IPV4) &&
- is_connected_state(service,
- CONNMAN_IPCONFIG_TYPE_IPV6);
+ return is_connected(service->state_ipv4) &&
+ is_connected(service->state_ipv6);
}
return false;
@@ -6415,7 +6660,7 @@ int __connman_service_get_connected_count_of_iface(
index2 = __connman_service_get_index(service2);
- if (is_connected(service2) && index2 > 0 && index1 == index2)
+ if (is_connected(service2->state) && index2 > 0 && index1 == index2)
count++;
index2 = 0;
@@ -6535,9 +6780,24 @@ void __connman_service_set_string(struct connman_service *service,
} else if (g_str_equal(key, "Identity")) {
g_free(service->identity);
service->identity = g_strdup(value);
+ } else if (g_str_equal(key, "AnonymousIdentity")) {
+ g_free(service->anonymous_identity);
+ service->anonymous_identity = g_strdup(value);
} else if (g_str_equal(key, "CACertFile")) {
g_free(service->ca_cert_file);
service->ca_cert_file = g_strdup(value);
+ } else if (g_str_equal(key, "SubjectMatch")) {
+ g_free(service->subject_match);
+ service->subject_match = g_strdup(value);
+ } else if (g_str_equal(key, "AltSubjectMatch")) {
+ g_free(service->altsubject_match);
+ service->altsubject_match = g_strdup(value);
+ } else if (g_str_equal(key, "DomainSuffixMatch")) {
+ g_free(service->domain_suffix_match);
+ service->domain_suffix_match = g_strdup(value);
+ } else if (g_str_equal(key, "DomainMatch")) {
+ g_free(service->domain_match);
+ service->domain_match = g_strdup(value);
} else if (g_str_equal(key, "ClientCertFile")) {
g_free(service->client_cert_file);
service->client_cert_file = g_strdup(value);
@@ -6567,17 +6827,6 @@ void __connman_service_set_search_domains(struct connman_service *service,
searchdomain_add_all(service);
}
-static void service_complete(struct connman_service *service)
-{
- reply_pending(service, EIO);
-
- if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
- __connman_service_auto_connect(service->connect_reason);
-
- g_get_current_time(&service->modified);
- service_save(service);
-}
-
static void report_error_cb(void *user_context, bool retry,
void *user_data)
{
@@ -6657,7 +6906,8 @@ static void request_input_cb(struct connman_service *service,
if (service->hidden)
__connman_service_return_error(service,
- ECANCELED, user_data);
+ ECONNABORTED,
+ user_data);
goto done;
} else {
if (service->hidden)
@@ -6738,7 +6988,7 @@ static void downgrade_connected_services(void)
for (list = service_list; list; list = list->next) {
up_service = list->data;
- if (!is_connected(up_service))
+ if (!is_connected(up_service->state))
continue;
if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
@@ -6781,7 +7031,7 @@ static int service_update_preferred_order(struct connman_service *default_servic
#if defined TIZEN_EXT
static gboolean __connman_service_can_drop(struct connman_service *service)
{
- if (is_connected(service) == TRUE || is_connecting(service) == TRUE) {
+ if (is_connected(service->state) == TRUE || is_connecting(service->state) == TRUE) {
if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
return TRUE;
else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
@@ -6849,7 +7099,7 @@ static void __connman_service_connect_default(struct connman_service *current)
}
return;
- } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE)
+ } else if (is_connected(current->state) == TRUE || is_connecting(current->state) == TRUE)
return;
/* Always-on: keep default cellular connection as possible */
@@ -6871,8 +7121,8 @@ static void __connman_service_connect_default(struct connman_service *current)
if (default_internet) {
default_service = service;
- if (is_connected(default_service) == TRUE ||
- is_connecting(default_service) == TRUE)
+ if (is_connected(default_service->state) == TRUE ||
+ is_connecting(default_service->state) == TRUE)
return;
default_device = connman_network_get_device(default_service->network);
@@ -6918,7 +7168,7 @@ static void single_connected_tech(struct connman_service *allowed)
if (service != allowed && service->type != allowed->type &&
__connman_service_can_drop(service) == TRUE)
#else
- if (!is_connected(service))
+ if (!is_connected(service->state))
break;
if (service == allowed)
@@ -6949,7 +7199,7 @@ static void set_priority_connected_service(void)
for (list = service_list; list; list = list->next) {
service = list->data;
- if (is_connected(service) == FALSE)
+ if (is_connected(service->state) == FALSE)
service->order = 5;
else
service->order = 6;
@@ -7000,13 +7250,15 @@ static int service_indicate_state(struct connman_service *service)
if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
__connman_notifier_leave_online(service->type);
- if (is_connected_state(service, old_state) &&
- !is_connected_state(service, new_state))
+ if (is_connected(old_state) && !is_connected(new_state))
searchdomain_remove_all(service);
service->state = new_state;
state_changed(service);
+ if (!is_connected(old_state) && is_connected(new_state))
+ searchdomain_add_all(service);
+
switch(new_state) {
case CONNMAN_SERVICE_STATE_UNKNOWN:
@@ -7065,17 +7317,6 @@ static int service_indicate_state(struct connman_service *service)
reply_pending(service, 0);
- g_get_current_time(&service->modified);
- service_save(service);
-
- searchdomain_add_all(service);
- dns_changed(service);
- domain_changed(service);
- proxy_changed(service);
-
- if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
- __connman_notifier_connect(service->type);
-
if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
connman_network_get_bool(service->network,
"WiFi.UseWPS")) {
@@ -7090,6 +7331,15 @@ static int service_indicate_state(struct connman_service *service)
"WiFi.UseWPS", false);
}
+ g_get_current_time(&service->modified);
+ service_save(service);
+
+ domain_changed(service);
+ proxy_changed(service);
+
+ if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
+ __connman_notifier_connect(service->type);
+
method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
if (method == CONNMAN_IPCONFIG_METHOD_OFF)
__connman_ipconfig_disable_ipv6(
@@ -7140,7 +7390,6 @@ static int service_indicate_state(struct connman_service *service)
__connman_service_get_connected_count_of_iface(
service) <= 0) {
#endif
- dns_changed(service);
domain_changed(service);
proxy_changed(service);
#if defined TIZEN_EXT
@@ -7159,9 +7408,6 @@ static int service_indicate_state(struct connman_service *service)
case CONNMAN_SERVICE_STATE_FAILURE:
#if defined TIZEN_EXT
-
- service->assoc_status_code = connman_network_get_assoc_status_code(service->network);
-
if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
service->order = 5;
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
@@ -7289,7 +7535,7 @@ int __connman_service_indicate_default(struct connman_service *service)
{
DBG("service %p state %s", service, state2string(service->state));
- if (!is_connected(service)) {
+ if (!is_connected(service->state)) {
/*
* If service is not yet fully connected, then we must not
* change the default yet. The default gw will be changed
@@ -7483,6 +7729,26 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
if (!ipconfig)
return -EINVAL;
+ method = __connman_ipconfig_get_method(ipconfig);
+
+ switch (method) {
+ case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+ case CONNMAN_IPCONFIG_METHOD_OFF:
+ if (new_state != CONNMAN_SERVICE_STATE_IDLE)
+ connman_warn("ipconfig state %d ipconfig method %d",
+ new_state, method);
+
+ new_state = CONNMAN_SERVICE_STATE_IDLE;
+ break;
+
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
+ case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ case CONNMAN_IPCONFIG_METHOD_DHCP:
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ break;
+
+ }
+
/* Any change? */
if (old_state == new_state)
return -EALREADY;
@@ -7507,11 +7773,9 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
switch (new_state) {
case CONNMAN_SERVICE_STATE_UNKNOWN:
- case CONNMAN_SERVICE_STATE_IDLE:
case CONNMAN_SERVICE_STATE_ASSOCIATION:
break;
case CONNMAN_SERVICE_STATE_CONFIGURATION:
- __connman_ipconfig_enable(ipconfig);
break;
case CONNMAN_SERVICE_STATE_READY:
#if defined TIZEN_EXT
@@ -7523,15 +7787,20 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
break;
}
#endif
- if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+ if (connman_setting_get_bool("EnableOnlineCheck")) {
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
#if !defined TIZEN_EXT
- check_proxy_setup(service);
+ check_proxy_setup(service);
#endif
+ } else {
+ service->online_check_count = 1;
+ __connman_wispr_start(service, type);
+ }
+ } else
+ connman_info("Online check disabled. "
+ "Default service remains in READY state.");
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
service_rp_filter(service, true);
- } else {
- service->online_check_count = 1;
- __connman_wispr_start(service, type);
- }
break;
case CONNMAN_SERVICE_STATE_ONLINE:
break;
@@ -7543,59 +7812,26 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
service_rp_filter(service, false);
break;
+
+ case CONNMAN_SERVICE_STATE_IDLE:
case CONNMAN_SERVICE_STATE_FAILURE:
- break;
- }
+ __connman_ipconfig_disable(ipconfig);
- /* Keep that state, but if the ipconfig method is OFF, then we set
- the state to IDLE so that it will not affect the combined state
- in the future.
- */
- method = __connman_ipconfig_get_method(ipconfig);
- switch (method) {
- case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
- case CONNMAN_IPCONFIG_METHOD_OFF:
- new_state = CONNMAN_SERVICE_STATE_IDLE;
break;
-
- case CONNMAN_IPCONFIG_METHOD_FIXED:
- case CONNMAN_IPCONFIG_METHOD_MANUAL:
- case CONNMAN_IPCONFIG_METHOD_DHCP:
- case CONNMAN_IPCONFIG_METHOD_AUTO:
- break;
-
}
- if (is_connected_state(service, old_state) &&
- !is_connected_state(service, new_state))
-#if defined TIZEN_EXT
- {
- DBG("nameserver remove all, type: %d", type);
+ if (is_connected(old_state) && !is_connected(new_state))
nameserver_remove_all(service, type);
-#else
- nameserver_remove_all(service);
-#endif
-#if defined TIZEN_EXT
- }
-#endif
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
service->state_ipv4 = new_state;
else
service->state_ipv6 = new_state;
- if (!is_connected_state(service, old_state) &&
- is_connected_state(service, new_state))
-#if defined TIZEN_EXT
- {
- DBG("nameserver add all, type: %d", type);
+ if (!is_connected(old_state) && is_connected(new_state))
nameserver_add_all(service, type);
-#else
- nameserver_add_all(service);
-#endif
-#if defined TIZEN_EXT
- }
-#endif
+
+ __connman_timeserver_sync(service);
#if defined TIZEN_EXT
int ret = service_indicate_state(service);
@@ -7654,10 +7890,31 @@ static void prepare_8021x(struct connman_service *service)
connman_network_set_string(service->network, "WiFi.Identity",
service->identity);
+ if (service->anonymous_identity)
+ connman_network_set_string(service->network,
+ "WiFi.AnonymousIdentity",
+ service->anonymous_identity);
+
if (service->ca_cert_file)
connman_network_set_string(service->network, "WiFi.CACertFile",
service->ca_cert_file);
+ if (service->subject_match)
+ connman_network_set_string(service->network, "WiFi.SubjectMatch",
+ service->subject_match);
+
+ if (service->altsubject_match)
+ connman_network_set_string(service->network, "WiFi.AltSubjectMatch",
+ service->altsubject_match);
+
+ if (service->domain_suffix_match)
+ connman_network_set_string(service->network, "WiFi.DomainSuffixMatch",
+ service->domain_suffix_match);
+
+ if (service->domain_match)
+ connman_network_set_string(service->network, "WiFi.DomainMatch",
+ service->domain_match);
+
if (service->client_cert_file)
connman_network_set_string(service->network,
"WiFi.ClientCertFile",
@@ -7697,7 +7954,7 @@ static int service_connect(struct connman_service *service)
if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
break;
- if (!is_connecting(temp) && !is_connected(temp))
+ if (!is_connecting(temp->state) && !is_connected(temp->state))
break;
if (service == temp)
@@ -7813,22 +8070,22 @@ static int service_connect(struct connman_service *service)
&service->stats_roaming.data);
}
- if (service->ipconfig_ipv4)
- __connman_ipconfig_enable(service->ipconfig_ipv4);
- if (service->ipconfig_ipv6)
- __connman_ipconfig_enable(service->ipconfig_ipv6);
-
err = __connman_network_connect(service->network);
} else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
service->provider)
- err = __connman_provider_connect(service->provider);
+ err = __connman_provider_connect(service->provider,
+ get_dbus_sender(service));
else
return -EOPNOTSUPP;
if (err < 0) {
if (err != -EINPROGRESS) {
- __connman_ipconfig_disable(service->ipconfig_ipv4);
- __connman_ipconfig_disable(service->ipconfig_ipv6);
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_FAILURE,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_FAILURE,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
__connman_stats_service_unregister(service);
}
}
@@ -7846,10 +8103,10 @@ int __connman_service_connect(struct connman_service *service,
reason2string(service->connect_reason),
reason2string(reason));
- if (is_connected(service))
+ if (is_connected(service->state))
return -EISCONN;
- if (is_connecting(service))
+ if (is_connecting(service->state))
return -EALREADY;
switch (service->type) {
@@ -7875,6 +8132,8 @@ int __connman_service_connect(struct connman_service *service,
err = service_connect(service);
+ DBG("service %p err %d", service, err);
+
service->connect_reason = reason;
if (err >= 0)
return 0;
@@ -7896,6 +8155,7 @@ int __connman_service_connect(struct connman_service *service,
if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
if (err == -ENOKEY || err == -EPERM) {
DBusMessage *pending = NULL;
+ const char *dbus_sender = get_dbus_sender(service);
/*
* We steal the reply here. The idea is that the
@@ -7910,7 +8170,7 @@ int __connman_service_connect(struct connman_service *service,
err = __connman_agent_request_passphrase_input(service,
request_input_cb,
- get_dbus_sender(service),
+ dbus_sender,
pending);
if (service->hidden && err != -EINPROGRESS)
service->pending = pending;
@@ -7992,7 +8252,7 @@ int __connman_service_disconnect_all(void)
for (iter = service_list; iter; iter = iter->next) {
service = iter->data;
- if (!is_connected(service))
+ if (!is_connected(service->state))
break;
services = g_slist_prepend(services, service);
@@ -8022,6 +8282,11 @@ static struct connman_service *lookup_by_identifier(const char *identifier)
return g_hash_table_lookup(service_hash, identifier);
}
+struct connman_service *connman_service_lookup_from_identifier(const char* identifier)
+{
+ return lookup_by_identifier(identifier);
+}
+
struct provision_user_data {
const char *ident;
int ret;
@@ -8172,12 +8437,6 @@ static void service_lower_down(struct connman_ipconfig *ipconfig,
DBG("%s lower down", ifname);
- if (!is_idle_state(service, service->state_ipv4))
- __connman_ipconfig_disable(service->ipconfig_ipv4);
-
- if (!is_idle_state(service, service->state_ipv6))
- __connman_ipconfig_disable(service->ipconfig_ipv6);
-
stats_stop(service);
service_save(service);
}
@@ -8206,9 +8465,8 @@ static void service_ip_bound(struct connman_ipconfig *ipconfig,
{
err = __connman_ipconfig_gateway_add(ipconfig, service);
- if(err == 0)
- __connman_connection_gateway_activate(service,
- CONNMAN_IPCONFIG_TYPE_IPV6);
+ if(err < 0)
+ DBG("Failed to add gateway");
}
#else
__connman_service_ipconfig_indicate_state(service,
@@ -8217,6 +8475,7 @@ static void service_ip_bound(struct connman_ipconfig *ipconfig,
#endif
settings_changed(service, ipconfig);
+ address_updated(service, type);
}
static void service_ip_release(struct connman_ipconfig *ipconfig,
@@ -8491,12 +8750,6 @@ unsigned int __connman_service_get_order(struct connman_service *service)
return order;
}
-void __connman_service_update_ordering(void)
-{
- if (service_list && service_list->next)
- service_list = g_list_sort(service_list, service_compare);
-}
-
static enum connman_service_type convert_network_type(struct connman_network *network)
{
enum connman_network_type type = connman_network_get_type(network);
@@ -8557,7 +8810,7 @@ int check_passphrase_ext(struct connman_network *network,
str = connman_network_get_string(network, "WiFi.Security");
security = convert_wifi_security(str);
- return check_passphrase(security, passphrase);
+ return __connman_service_check_passphrase(security, passphrase);
}
#endif
@@ -8569,10 +8822,10 @@ static void update_from_network(struct connman_service *service,
DBG("service %p network %p", service, network);
- if (is_connected(service))
+ if (is_connected(service->state))
return;
- if (is_connecting(service))
+ if (is_connecting(service->state))
return;
str = connman_network_get_string(network, "Name");
@@ -8704,6 +8957,7 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
service->ipconfig_ipv6 = create_ip6config(service, index);
service_register(service);
+ service_schedule_added(service);
if (service->favorite) {
device = connman_network_get_device(service->network);
@@ -8749,7 +9003,6 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
}
__connman_notifier_service_add(service, service->name);
- service_schedule_added(service);
return service;
}
@@ -9012,6 +9265,8 @@ int __connman_service_init(void)
return err;
}
+ set_always_connecting_technologies();
+
connection = connman_dbus_get_connection();
service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
@@ -9055,9 +9310,10 @@ void __connman_service_cleanup(void)
if (services_notify->id != 0) {
g_source_remove(services_notify->id);
service_send_changed(NULL);
- g_hash_table_destroy(services_notify->remove);
- g_hash_table_destroy(services_notify->add);
}
+
+ g_hash_table_destroy(services_notify->remove);
+ g_hash_table_destroy(services_notify->add);
g_free(services_notify);
dbus_connection_unref(connection);
diff --git a/src/session.c b/src/session.c
index 08facc1d..9e3c5594 100755
--- a/src/session.c
+++ b/src/session.c
@@ -37,13 +37,6 @@ static GHashTable *session_hash;
static GHashTable *service_hash;
static struct connman_session *ecall_session;
static uint32_t session_mark = 256;
-static struct firewall_context *global_firewall = NULL;
-
-enum connman_session_state {
- CONNMAN_SESSION_STATE_DISCONNECTED = 0,
- CONNMAN_SESSION_STATE_CONNECTED = 1,
- CONNMAN_SESSION_STATE_ONLINE = 2,
-};
struct session_info {
struct connman_session_config config;
@@ -64,6 +57,7 @@ struct connman_session {
struct connman_service *service_last;
struct connman_session_config *policy_config;
GSList *user_allowed_bearers;
+ char *user_allowed_interface;
bool ecall;
@@ -73,6 +67,7 @@ struct connman_session {
int index;
char *gateway;
bool policy_routing;
+ bool snat_enabled;
};
struct connman_service_info {
@@ -80,6 +75,15 @@ struct connman_service_info {
GSList *sessions;
};
+struct fw_snat {
+ GSList *sessions;
+ int id;
+ int index;
+ struct firewall_context *fw;
+};
+
+GSList *fw_snat_list;
+
static struct connman_session_policy *policy;
static void session_activate(struct connman_session *session);
static void session_deactivate(struct connman_session *session);
@@ -196,102 +200,109 @@ static char *service2bearer(enum connman_service_type type)
return "";
}
-static int init_firewall(void)
+static struct fw_snat *fw_snat_lookup(int index)
{
- struct firewall_context *fw;
- int err;
+ struct fw_snat *fw_snat;
+ GSList *list;
- if (global_firewall)
- return 0;
+ for (list = fw_snat_list; list; list = list->next) {
+ fw_snat = list->data;
- fw = __connman_firewall_create();
+ if (fw_snat->index == index)
+ return fw_snat;
+ }
+ return NULL;
+}
- err = __connman_firewall_add_rule(fw, "mangle", "INPUT",
- "-j CONNMARK --restore-mark");
- if (err < 0)
- goto err;
+static int fw_snat_create(struct connman_session *session,
+ int index, const char *ifname, const char *addr)
+{
+ struct fw_snat *fw_snat;
+ int err;
- err = __connman_firewall_add_rule(fw, "mangle", "POSTROUTING",
- "-j CONNMARK --save-mark");
- if (err < 0)
- goto err;
+ fw_snat = g_new0(struct fw_snat, 1);
- err = __connman_firewall_enable(fw);
- if (err < 0)
+ fw_snat->fw = __connman_firewall_create();
+ fw_snat->index = index;
+
+ fw_snat->id = __connman_firewall_enable_snat(fw_snat->fw,
+ index, ifname, addr);
+ if (fw_snat->id < 0) {
+ err = fw_snat->id;
goto err;
+ }
- global_firewall = fw;
+ fw_snat_list = g_slist_prepend(fw_snat_list, fw_snat);
+ fw_snat->sessions = g_slist_prepend(fw_snat->sessions, session);
return 0;
-
err:
- __connman_firewall_destroy(fw);
-
+ __connman_firewall_destroy(fw_snat->fw);
+ g_free(fw_snat);
return err;
}
-static void cleanup_firewall(void)
+static void fw_snat_ref(struct connman_session *session,
+ struct fw_snat *fw_snat)
{
- if (!global_firewall)
+ if (g_slist_find(fw_snat->sessions, session))
return;
+ fw_snat->sessions = g_slist_prepend(fw_snat->sessions, session);
+}
- __connman_firewall_disable(global_firewall);
- __connman_firewall_destroy(global_firewall);
+static void fw_snat_unref(struct connman_session *session,
+ struct fw_snat *fw_snat)
+{
+ fw_snat->sessions = g_slist_remove(fw_snat->sessions, session);
+ if (fw_snat->sessions)
+ return;
+
+ fw_snat_list = g_slist_remove(fw_snat_list, fw_snat);
+
+ __connman_firewall_disable_snat(fw_snat->fw);
+ __connman_firewall_destroy(fw_snat->fw);
+ g_free(fw_snat);
}
static int init_firewall_session(struct connman_session *session)
{
struct firewall_context *fw;
int err;
+ struct connman_ipconfig *ipconfig = NULL;
+ const char *addr = NULL;
- if (session->policy_config->id_type == CONNMAN_SESSION_ID_TYPE_UNKNOWN)
+ if (session->policy_config->id_type == CONNMAN_SESSION_ID_TYPE_UNKNOWN &&
+ !session->info->config.source_ip_rule)
return 0;
DBG("");
- err = init_firewall();
- if (err < 0)
- return err;
+ if (session->info->config.source_ip_rule) {
+ ipconfig = __connman_service_get_ip4config(session->service);
+ if (session->policy_config->id_type == CONNMAN_SESSION_ID_TYPE_UNKNOWN && !ipconfig)
+ return 0;
+ }
fw = __connman_firewall_create();
if (!fw)
return -ENOMEM;
- switch (session->policy_config->id_type) {
- case CONNMAN_SESSION_ID_TYPE_UID:
- err = __connman_firewall_add_rule(fw, "mangle", "OUTPUT",
- "-m owner --uid-owner %s -j MARK --set-mark %d",
- session->policy_config->id,
- session->mark);
- break;
- case CONNMAN_SESSION_ID_TYPE_GID:
- err = __connman_firewall_add_rule(fw, "mangle", "OUTPUT",
- "-m owner --gid-owner %s -j MARK --set-mark %d",
- session->policy_config->id,
- session->mark);
- break;
- case CONNMAN_SESSION_ID_TYPE_LSM:
- default:
- err = -EINVAL;
+ if (session->info->config.source_ip_rule && ipconfig) {
+ addr = __connman_ipconfig_get_local(ipconfig);
}
- if (err < 0)
- goto err;
-
+ err =__connman_firewall_enable_marking(fw,
+ session->policy_config->id_type,
+ session->policy_config->id,
+ addr, session->mark);
+ if (err < 0) {
+ __connman_firewall_destroy(fw);
+ return err;
+ }
session->id_type = session->policy_config->id_type;
-
- err = __connman_firewall_enable(fw);
- if (err)
- goto err;
-
session->fw = fw;
return 0;
-
-err:
- __connman_firewall_destroy(fw);
-
- return err;
}
static void cleanup_firewall_session(struct connman_session *session)
@@ -299,7 +310,8 @@ static void cleanup_firewall_session(struct connman_session *session)
if (!session->fw)
return;
- __connman_firewall_disable(session->fw);
+ __connman_firewall_disable_marking(session->fw);
+ __connman_firewall_disable_snat(session->fw);
__connman_firewall_destroy(session->fw);
session->fw = NULL;
@@ -309,7 +321,11 @@ static int init_routing_table(struct connman_session *session)
{
int err;
- if (session->policy_config->id_type == CONNMAN_SESSION_ID_TYPE_UNKNOWN)
+ if (session->policy_config->id_type == CONNMAN_SESSION_ID_TYPE_UNKNOWN &&
+ !session->info->config.source_ip_rule)
+ return 0;
+
+ if (!session->service)
return 0;
DBG("");
@@ -348,6 +364,7 @@ static void add_default_route(struct connman_session *session)
{
struct connman_ipconfig *ipconfig;
int err;
+ struct in_addr addr = { INADDR_ANY };
if (!session->service)
return;
@@ -356,6 +373,9 @@ static void add_default_route(struct connman_session *session)
session->index = __connman_ipconfig_get_index(ipconfig);
session->gateway = g_strdup(__connman_ipconfig_get_gateway(ipconfig));
+ if (!session->gateway)
+ session->gateway = g_strdup(inet_ntoa(addr));
+
DBG("index %d routing table %d default gateway %s",
session->index, session->mark, session->gateway);
@@ -365,6 +385,62 @@ static void add_default_route(struct connman_session *session)
DBG("session %p %s", session, strerror(-err));
}
+static void del_nat_rules(struct connman_session *session)
+{
+ struct fw_snat *fw_snat;
+
+ if (!session->snat_enabled)
+ return;
+
+ session->snat_enabled = false;
+ fw_snat = fw_snat_lookup(session->index);
+
+ if (!fw_snat)
+ return;
+
+ fw_snat_unref(session, fw_snat);
+}
+
+static void add_nat_rules(struct connman_session *session)
+{
+ struct connman_ipconfig *ipconfig;
+ struct fw_snat *fw_snat;
+ const char *addr;
+ int index, err;
+ char *ifname;
+
+ if (!session->service)
+ return;
+
+ ipconfig = __connman_service_get_ip4config(session->service);
+ index = __connman_ipconfig_get_index(ipconfig);
+ ifname = connman_inet_ifname(index);
+ addr = __connman_ipconfig_get_local(ipconfig);
+
+ if (!addr)
+ return;
+
+ session->snat_enabled = true;
+ fw_snat = fw_snat_lookup(index);
+ if (fw_snat) {
+ fw_snat_ref(session, fw_snat);
+ return;
+ }
+
+ err = fw_snat_create(session, index, ifname, addr);
+ if (err < 0) {
+ DBG("failed to add SNAT rule");
+ session->snat_enabled = false;
+ }
+
+ g_free(ifname);
+}
+
+uint32_t connman_session_firewall_get_fwmark(struct connman_session *session)
+{
+ return session->mark;
+}
+
static void cleanup_routing_table(struct connman_session *session)
{
DBG("");
@@ -381,12 +457,24 @@ static void cleanup_routing_table(struct connman_session *session)
del_default_route(session);
}
+static void update_firewall(struct connman_session *session)
+{
+ cleanup_firewall_session(session);
+ init_firewall_session(session);
+}
+
static void update_routing_table(struct connman_session *session)
{
- del_default_route(session);
+ cleanup_routing_table(session);
+ init_routing_table(session);
add_default_route(session);
}
+static void cleanup_nat_rules(struct connman_session *session)
+{
+ del_nat_rules(session);
+}
+
static void destroy_policy_config(struct connman_session *session)
{
if (!policy) {
@@ -407,6 +495,7 @@ static void free_session(struct connman_session *session)
destroy_policy_config(session);
g_slist_free(session->info->config.allowed_bearers);
+ g_free(session->info->config.allowed_interface);
g_free(session->owner);
g_free(session->session_path);
g_free(session->notify_path);
@@ -434,6 +523,7 @@ static void cleanup_session(gpointer user_data)
DBG("remove %s", session->session_path);
+ cleanup_nat_rules(session);
cleanup_routing_table(session);
cleanup_firewall_session(session);
@@ -444,6 +534,7 @@ static void cleanup_session(gpointer user_data)
update_session_state(session);
g_slist_free(session->user_allowed_bearers);
+ g_free(session->user_allowed_interface);
free_session(session);
}
@@ -455,6 +546,8 @@ struct creation_data {
/* user config */
enum connman_session_type type;
GSList *allowed_bearers;
+ char *allowed_interface;
+ bool source_ip_rule;
};
static void cleanup_creation_data(struct creation_data *creation_data)
@@ -466,6 +559,7 @@ static void cleanup_creation_data(struct creation_data *creation_data)
dbus_message_unref(creation_data->pending);
g_slist_free(creation_data->allowed_bearers);
+ g_free(creation_data->allowed_interface);
g_free(creation_data);
}
@@ -543,6 +637,7 @@ void connman_session_set_default_config(struct connman_session_config *config)
config->ecall = FALSE;
g_slist_free(config->allowed_bearers);
+ config->allowed_bearers = NULL;
add_default_bearer_types(&config->allowed_bearers);
}
@@ -628,18 +723,18 @@ static int parse_bearers(DBusMessageIter *iter, GSList **list)
return 0;
}
-static void filter_bearer(GSList *policy_bearers,
- enum connman_service_type bearer,
+static void filter_bearer(GSList *bearers,
+ enum connman_service_type policy,
GSList **list)
{
- enum connman_service_type policy;
+ enum connman_service_type bearer;
GSList *it;
- if (!policy_bearers)
+ if (!bearers)
return;
- for (it = policy_bearers; it; it = it->next) {
- policy = GPOINTER_TO_INT(it->data);
+ for (it = bearers; it; it = it->next) {
+ bearer = GPOINTER_TO_INT(it->data);
if (policy != bearer)
continue;
@@ -652,18 +747,29 @@ static void filter_bearer(GSList *policy_bearers,
static void apply_policy_on_bearers(GSList *policy_bearers, GSList *bearers,
GSList **list)
{
- enum connman_service_type bearer;
+ enum connman_service_type policy_bearer;
GSList *it;
*list = NULL;
- for (it = bearers; it; it = it->next) {
- bearer = GPOINTER_TO_INT(it->data);
+ for (it = policy_bearers; it; it = it->next) {
+ policy_bearer = GPOINTER_TO_INT(it->data);
- filter_bearer(policy_bearers, bearer, list);
+ filter_bearer(bearers, policy_bearer, list);
}
}
+static char * apply_policy_on_interface(const char *policy_interface,
+ const char *user_interface)
+{
+ if (policy_interface)
+ return g_strdup(policy_interface);
+ else if (user_interface)
+ return g_strdup(user_interface);
+ else
+ return NULL;
+}
+
const char *connman_session_get_owner(struct connman_session *session)
{
return session->owner;
@@ -809,6 +915,28 @@ static void append_notify(DBusMessageIter *dict,
info_last->config.allowed_bearers = info->config.allowed_bearers;
}
+ if (session->append_all ||
+ info->config.allowed_interface != info_last->config.allowed_interface) {
+ char *ifname = info->config.allowed_interface;
+ if (!ifname)
+ ifname = "*";
+ connman_dbus_dict_append_basic(dict, "AllowedInterface",
+ DBUS_TYPE_STRING,
+ &ifname);
+ info_last->config.allowed_interface = info->config.allowed_interface;
+ }
+
+ if (session->append_all ||
+ info->config.source_ip_rule != info_last->config.source_ip_rule) {
+ dbus_bool_t source_ip_rule = FALSE;
+ if (info->config.source_ip_rule)
+ source_ip_rule = TRUE;
+ connman_dbus_dict_append_basic(dict, "SourceIPRule",
+ DBUS_TYPE_BOOLEAN,
+ &source_ip_rule);
+ info_last->config.source_ip_rule = info->config.source_ip_rule;
+ }
+
session->append_all = false;
}
@@ -828,7 +956,9 @@ static bool compute_notifiable_changes(struct connman_session *session)
return true;
if (info->config.allowed_bearers != info_last->config.allowed_bearers ||
- info->config.type != info_last->config.type)
+ info->config.type != info_last->config.type ||
+ info->config.allowed_interface != info_last->config.allowed_interface ||
+ info->config.source_ip_rule != info_last->config.source_ip_rule)
return true;
return false;
@@ -882,6 +1012,7 @@ int connman_session_config_update(struct connman_session *session)
{
struct session_info *info = session->info;
GSList *allowed_bearers;
+ char *allowed_interface;
int err;
DBG("session %p", session);
@@ -907,6 +1038,10 @@ int connman_session_config_update(struct connman_session *session)
session->user_allowed_bearers,
&allowed_bearers);
+ allowed_interface = apply_policy_on_interface(
+ session->policy_config->allowed_interface,
+ session->user_allowed_interface);
+
if (session->active)
set_active_session(session, false);
@@ -916,6 +1051,9 @@ int connman_session_config_update(struct connman_session *session)
g_slist_free(info->config.allowed_bearers);
info->config.allowed_bearers = allowed_bearers;
+ g_free(info->config.allowed_interface);
+ info->config.allowed_interface = allowed_interface;
+
session_activate(session);
info->config.type = apply_policy_on_type(
@@ -1024,6 +1162,7 @@ static DBusMessage *change_session(DBusConnection *conn,
session->active = false;
session_deactivate(session);
+ update_session_state(session);
g_slist_free(info->config.allowed_bearers);
session->user_allowed_bearers = allowed_bearers;
@@ -1044,6 +1183,38 @@ static DBusMessage *change_session(DBusConnection *conn,
info->config.type = apply_policy_on_type(
session->policy_config->type,
connman_session_parse_connection_type(val));
+ } else if (g_str_equal(name, "AllowedInterface")) {
+ dbus_message_iter_get_basic(&value, &val);
+ if (session->active)
+ set_active_session(session, false);
+
+ session->active = false;
+ session_deactivate(session);
+ update_session_state(session);
+
+ g_free(session->user_allowed_interface);
+ /* empty string means allow any interface */
+ if (!g_strcmp0(val, ""))
+ session->user_allowed_interface = NULL;
+ else
+ session->user_allowed_interface = g_strdup(val);
+
+ info->config.allowed_interface = apply_policy_on_interface(
+ session->policy_config->allowed_interface,
+ session->user_allowed_interface);
+
+ session_activate(session);
+ } else {
+ goto err;
+ }
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ if (g_str_equal(name, "SourceIPRule")) {
+ dbus_bool_t source_ip_rule;
+ dbus_message_iter_get_basic(&value, &source_ip_rule);
+
+ info->config.source_ip_rule = source_ip_rule;
+ update_session_state(session);
} else {
goto err;
}
@@ -1149,6 +1320,7 @@ static int session_policy_config_cb(struct connman_session *session,
goto err;
session->policy_config = config;
+ session->info->config.source_ip_rule = creation_data->source_ip_rule;
session->mark = session_mark++;
session->index = -1;
@@ -1177,11 +1349,18 @@ static int session_policy_config_cb(struct connman_session *session,
session->user_allowed_bearers = creation_data->allowed_bearers;
creation_data->allowed_bearers = NULL;
+ session->user_allowed_interface = creation_data->allowed_interface;
+ creation_data->allowed_interface = NULL;
+
apply_policy_on_bearers(
session->policy_config->allowed_bearers,
session->user_allowed_bearers,
&info->config.allowed_bearers);
+ info->config.allowed_interface = apply_policy_on_interface(
+ session->policy_config->allowed_interface,
+ session->user_allowed_interface);
+
g_hash_table_replace(session_hash, session->session_path, session);
DBG("add %s", session->session_path);
@@ -1206,6 +1385,8 @@ static int session_policy_config_cb(struct connman_session *session,
info_last->config.priority = info->config.priority;
info_last->config.roaming_policy = info->config.roaming_policy;
info_last->config.allowed_bearers = info->config.allowed_bearers;
+ info_last->config.allowed_interface = info->config.allowed_interface;
+ info_last->config.source_ip_rule = info->config.source_ip_rule;
session->append_all = true;
@@ -1293,11 +1474,29 @@ int __connman_session_create(DBusMessage *msg)
connman_session_parse_connection_type(val);
user_connection_type = true;
+ } else if (g_str_equal(key, "AllowedInterface")) {
+ dbus_message_iter_get_basic(&value, &val);
+ creation_data->allowed_interface = g_strdup(val);
} else {
err = -EINVAL;
goto err;
}
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ if (g_str_equal(key, "SourceIPRule")) {
+ dbus_bool_t source_ip_rule;
+ dbus_message_iter_get_basic(&value, &source_ip_rule);
+ creation_data->source_ip_rule = source_ip_rule;
+ } else {
+ err = -EINVAL;
+ goto err;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ goto err;
}
+
dbus_message_iter_next(&array);
}
@@ -1481,7 +1680,14 @@ static void update_session_state(struct connman_session *session)
DBG("session %p state %s", session, state2string(state));
+ update_firewall(session);
+ del_nat_rules(session);
update_routing_table(session);
+ add_nat_rules(session);
+
+ if (policy && policy->update_session_state)
+ policy->update_session_state(session, state);
+
session_notify(session);
}
@@ -1490,17 +1696,31 @@ static bool session_match_service(struct connman_session *session,
{
enum connman_service_type bearer_type;
enum connman_service_type service_type;
+ enum connman_service_type current_service_type;
GSList *list;
+ char *ifname;
if (policy && policy->allowed)
return policy->allowed(session, service);
+ current_service_type = connman_service_get_type(session->service);
+
for (list = session->info->config.allowed_bearers; list; list = list->next) {
bearer_type = GPOINTER_TO_INT(list->data);
service_type = connman_service_get_type(service);
+ ifname = connman_service_get_interface(service);
- if (bearer_type == service_type)
- return true;
+ if (bearer_type == current_service_type)
+ return false;
+
+ if (bearer_type == service_type &&
+ (session->info->config.allowed_interface == NULL ||
+ !g_strcmp0(session->info->config.allowed_interface, "*") ||
+ !g_strcmp0(session->info->config.allowed_interface, ifname))) {
+ g_free(ifname);
+ return true;
+ }
+ g_free(ifname);
}
return false;
@@ -1521,6 +1741,7 @@ static bool is_session_connected(struct connman_session *session,
case CONNMAN_SERVICE_STATE_READY:
if (session->info->config.type == CONNMAN_SESSION_TYPE_INTERNET)
return false;
+ /* fall through */
case CONNMAN_SERVICE_STATE_ONLINE:
return true;
}
@@ -1536,6 +1757,40 @@ static void session_activate(struct connman_session *session)
if (!service_hash)
return;
+ if (policy && policy->get_service_for_session) {
+ struct connman_service *service;
+ struct connman_service_info *info;
+ GSList *service_list = NULL;
+ enum connman_service_state state = CONNMAN_SESSION_STATE_DISCONNECTED;
+
+ g_hash_table_iter_init(&iter, service_hash);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ struct connman_service_info *info = value;
+ state = __connman_service_get_state(info->service);
+
+ if (is_session_connected(session, state))
+ service_list = g_slist_prepend(service_list,
+ info->service);
+ }
+
+ service_list = g_slist_reverse(service_list);
+ service = policy->get_service_for_session(session, service_list);
+
+ if (service) {
+ info = g_hash_table_lookup(service_hash, service);
+ DBG("session %p add service %p", session, info->service);
+
+ info->sessions = g_slist_prepend(info->sessions,
+ session);
+ session->service = info->service;
+ update_session_state(session);
+ }
+
+ g_slist_free(service_list);
+ return;
+ }
+
g_hash_table_iter_init(&iter, service_hash);
while (g_hash_table_iter_next(&iter, &key, &value)) {
struct connman_service_info *info = value;
@@ -1630,10 +1885,10 @@ static void handle_service_state_offline(struct connman_service *service,
session->service = NULL;
update_session_state(session);
+ session_activate(session);
}
}
-
static void service_state_changed(struct connman_service *service,
enum connman_service_state state)
{
@@ -1693,7 +1948,7 @@ static void ipconfig_changed(struct connman_service *service,
continue;
if (session->service && session->service == service) {
- update_routing_table(session);
+ update_session_state(session);
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
ipconfig_ipv4_changed(session);
@@ -1730,12 +1985,6 @@ int __connman_session_init(void)
service_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, cleanup_service);
- if (__connman_firewall_is_up()) {
- err = init_firewall();
- if (err < 0)
- return err;
- }
-
return 0;
}
@@ -1746,8 +1995,6 @@ void __connman_session_cleanup(void)
if (!connection)
return;
- cleanup_firewall();
-
connman_notifier_unregister(&session_notifier);
g_hash_table_foreach(session_hash, release_session, NULL);
diff --git a/src/stats.c b/src/stats.c
index 26343b13..663bc382 100755
--- a/src/stats.c
+++ b/src/stats.c
@@ -227,18 +227,14 @@ static void stats_free(gpointer user_data)
munmap(file->addr, file->len);
file->addr = NULL;
- TFR(close(file->fd));
+ close(file->fd);
file->fd = -1;
- if (file->history_name) {
- g_free(file->history_name);
- file->history_name = NULL;
- }
+ g_free(file->history_name);
+ file->history_name = NULL;
- if (file->name) {
- g_free(file->name);
- file->name = NULL;
- }
+ g_free(file->name);
+ file->name = NULL;
g_free(file);
}
@@ -377,7 +373,8 @@ static int stats_file_setup(struct stats_file *file)
connman_error("fstat error %s for %s\n",
strerror(errno), file->name);
- TFR(close(file->fd));
+ close(file->fd);
+ file->fd = -1;
g_free(file->name);
file->name = NULL;
@@ -392,7 +389,8 @@ static int stats_file_setup(struct stats_file *file)
err = stats_file_remap(file, size);
if (err < 0) {
- TFR(close(file->fd));
+ close(file->fd);
+ file->fd = -1;
g_free(file->name);
file->name = NULL;
@@ -621,7 +619,7 @@ static int stats_file_close_swap(struct stats_file *history_file,
stats_file_unmap(history_file);
stats_file_unmap(temp_file);
- TFR(close(temp_file->fd));
+ close(temp_file->fd);
unlink(history_file->name);
@@ -629,7 +627,7 @@ static int stats_file_close_swap(struct stats_file *history_file,
unlink(temp_file->name);
- TFR(close(history_file->fd));
+ close(history_file->fd);
stats_file_cleanup(history_file);
stats_file_cleanup(temp_file);
@@ -649,6 +647,9 @@ static int stats_file_history_update(struct stats_file *data_file)
bzero(history_file, sizeof(struct stats_file));
bzero(temp_file, sizeof(struct stats_file));
+ history_file->fd = -1;
+ temp_file->fd = -1;
+
err = stats_open(history_file, data_file->history_name);
if (err < 0)
return err;
@@ -676,17 +677,6 @@ int __connman_stats_service_register(struct connman_service *service)
DBG("service %p", service);
- file = g_hash_table_lookup(stats_hash, service);
- if (!file) {
- file = g_try_new0(struct stats_file, 1);
- if (!file)
- return -ENOMEM;
-
- g_hash_table_insert(stats_hash, service, file);
- } else {
- return -EALREADY;
- }
-
dir = g_strdup_printf("%s/%s", STORAGEDIR,
__connman_service_get_ident(service));
@@ -703,6 +693,18 @@ int __connman_stats_service_register(struct connman_service *service)
}
g_free(dir);
+ file = g_hash_table_lookup(stats_hash, service);
+ if (!file) {
+ file = g_try_new0(struct stats_file, 1);
+ if (!file)
+ return -ENOMEM;
+
+ file->fd = -1;
+
+ g_hash_table_insert(stats_hash, service, file);
+ } else {
+ return -EALREADY;
+ }
name = g_strdup_printf("%s/%s/data", STORAGEDIR,
__connman_service_get_ident(service));
diff --git a/src/storage.c b/src/storage.c
index 2da54d6c..50c8e955 100755
--- a/src/storage.c
+++ b/src/storage.c
@@ -44,8 +44,6 @@ static GKeyFile *storage_load(const char *pathname)
GKeyFile *keyfile = NULL;
GError *error = NULL;
- DBG("Loading %s", pathname);
-
keyfile = g_key_file_new();
if (!g_key_file_load_from_file(keyfile, pathname, 0, &error)) {
diff --git a/src/task.c b/src/task.c
index 8b9e1d93..953cc409 100755
--- a/src/task.c
+++ b/src/task.c
@@ -401,8 +401,7 @@ int connman_task_stop(struct connman_task *task)
if (task->pid > 0) {
kill(task->pid, SIGTERM);
- g_timeout_add_seconds(0, check_kill,
- GINT_TO_POINTER(task->pid));
+ g_idle_add(check_kill, GINT_TO_POINTER(task->pid));
}
return 0;
diff --git a/src/technology.c b/src/technology.c
index 408c99f1..5aea9f4f 100755
--- a/src/technology.c
+++ b/src/technology.c
@@ -225,22 +225,27 @@ static void tethering_changed(struct connman_technology *technology)
technology_save(technology);
}
-void connman_technology_tethering_notify(struct connman_technology *technology,
+int connman_technology_tethering_notify(struct connman_technology *technology,
bool enabled)
{
+ int err;
+
DBG("technology %p enabled %u", technology, enabled);
if (technology->tethering == enabled)
- return;
+ return -EALREADY;
- technology->tethering = enabled;
+ if (enabled) {
+ err = __connman_tethering_set_enabled();
+ if (err < 0)
+ return err;
+ } else
+ __connman_tethering_set_disabled();
+ technology->tethering = enabled;
tethering_changed(technology);
- if (enabled)
- __connman_tethering_set_enabled();
- else
- __connman_tethering_set_disabled();
+ return 0;
}
static int set_tethering(struct connman_technology *technology,
@@ -250,11 +255,9 @@ static int set_tethering(struct connman_technology *technology,
int err;
const char *ident, *passphrase, *bridge;
GSList *tech_drivers;
- bool hidden;
ident = technology->tethering_ident;
passphrase = technology->tethering_passphrase;
- hidden = technology->tethering_hidden;
__sync_synchronize();
if (!technology->enabled)
@@ -275,15 +278,13 @@ static int set_tethering(struct connman_technology *technology,
continue;
err = driver->set_tethering(technology, ident, passphrase,
- bridge, enabled, hidden);
+ bridge, enabled);
if (result == -EINPROGRESS)
continue;
- if (err == -EINPROGRESS || err == 0) {
+ if (err == -EINPROGRESS || err == 0)
result = err;
- continue;
- }
}
return result;
@@ -459,15 +460,31 @@ bool __connman_technology_get_offlinemode(void)
static void connman_technology_save_offlinemode(void)
{
GKeyFile *keyfile;
+ GError *error = NULL;
+ bool offlinemode;
keyfile = __connman_storage_load_global();
- if (!keyfile)
+
+ if (!keyfile) {
keyfile = g_key_file_new();
+ g_key_file_set_boolean(keyfile, "global",
+ "OfflineMode", global_offlinemode);
- g_key_file_set_boolean(keyfile, "global",
+ __connman_storage_save_global(keyfile);
+ }
+ else {
+ offlinemode = g_key_file_get_boolean(keyfile, "global",
+ "OfflineMode", &error);
+
+ if (error || offlinemode != global_offlinemode) {
+ g_key_file_set_boolean(keyfile, "global",
"OfflineMode", global_offlinemode);
+ if (error)
+ g_clear_error(&error);
- __connman_storage_save_global(keyfile);
+ __connman_storage_save_global(keyfile);
+ }
+ }
g_key_file_free(keyfile);
@@ -865,7 +882,7 @@ static DBusMessage *set_property(DBusConnection *conn,
struct connman_technology *technology = data;
DBusMessageIter iter, value;
const char *name;
- int type;
+ int type, err;
DBG("conn %p", conn);
@@ -962,30 +979,21 @@ static DBusMessage *set_property(DBusConnection *conn,
if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
return __connman_error_not_supported(msg);
- if (strlen(str) < 8 || strlen(str) > 63) {
- if (g_str_equal(str, "")) {
- technology->tethering_passphrase = NULL;
+ err = __connman_service_check_passphrase(CONNMAN_SERVICE_SECURITY_PSK,
+ str);
+ if (err < 0)
+ return __connman_error_passphrase_required(msg);
- connman_dbus_property_changed_basic(technology->path,
- CONNMAN_TECHNOLOGY_INTERFACE,
- "TetheringPassphrase",
- DBUS_TYPE_STRING,
- &str);
- }
- else
- return __connman_error_passphrase_required(msg);
- } else {
- if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
- g_free(technology->tethering_passphrase);
- technology->tethering_passphrase = g_strdup(str);
- technology_save(technology);
+ if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
+ g_free(technology->tethering_passphrase);
+ technology->tethering_passphrase = g_strdup(str);
+ technology_save(technology);
- connman_dbus_property_changed_basic(technology->path,
- CONNMAN_TECHNOLOGY_INTERFACE,
- "TetheringPassphrase",
- DBUS_TYPE_STRING,
- &technology->tethering_passphrase);
- }
+ connman_dbus_property_changed_basic(technology->path,
+ CONNMAN_TECHNOLOGY_INTERFACE,
+ "TetheringPassphrase",
+ DBUS_TYPE_STRING,
+ &technology->tethering_passphrase);
}
} else if (g_str_equal(name, "Hidden")) {
dbus_bool_t hidden;
@@ -1178,6 +1186,10 @@ static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
DBG("technology %p request from %s", technology,
dbus_message_get_sender(msg));
+ if (technology->type == CONNMAN_SERVICE_TYPE_P2P &&
+ !technology->enabled)
+ return __connman_error_permission_denied(msg);
+
dbus_message_ref(msg);
#if !defined TIZEN_EXT
technology->scan_pending =
@@ -1423,6 +1435,13 @@ static void technology_put(struct connman_technology *technology)
g_slist_free(technology->device_list);
+ if (technology->pending_reply) {
+ dbus_message_unref(technology->pending_reply);
+ technology->pending_reply = NULL;
+ g_source_remove(technology->pending_timeout);
+ technology->pending_timeout = 0;
+ }
+
g_free(technology->path);
g_free(technology->regdom);
g_free(technology->tethering_ident);
diff --git a/src/tethering.c b/src/tethering.c
index c0c97431..891ee51f 100755
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -346,7 +346,7 @@ static void tethering_restart(struct connman_ippool *pool, void *user_data)
__connman_tethering_set_enabled();
}
-void __connman_tethering_set_enabled(void)
+int __connman_tethering_set_enabled(void)
{
int index;
int err;
@@ -362,12 +362,12 @@ void __connman_tethering_set_enabled(void)
DBG("enabled %d", tethering_enabled + 1);
if (__sync_fetch_and_add(&tethering_enabled, 1) != 0)
- return;
+ return 0;
err = __connman_bridge_create(BRIDGE_NAME);
if (err < 0) {
__sync_fetch_and_sub(&tethering_enabled, 1);
- return;
+ return -EOPNOTSUPP;
}
index = connman_inet_ifindex(BRIDGE_NAME);
@@ -377,7 +377,7 @@ void __connman_tethering_set_enabled(void)
connman_error("Fail to create IP pool");
__connman_bridge_remove(BRIDGE_NAME);
__sync_fetch_and_sub(&tethering_enabled, 1);
- return;
+ return -EADDRNOTAVAIL;
}
gateway = __connman_ippool_get_gateway(dhcp_ippool);
@@ -393,7 +393,7 @@ void __connman_tethering_set_enabled(void)
__connman_ippool_unref(dhcp_ippool);
__connman_bridge_remove(BRIDGE_NAME);
__sync_fetch_and_sub(&tethering_enabled, 1);
- return;
+ return -EADDRNOTAVAIL;
}
ns = connman_setting_get_string_list("FallbackNameservers");
@@ -429,7 +429,7 @@ void __connman_tethering_set_enabled(void)
__connman_ippool_unref(dhcp_ippool);
__connman_bridge_remove(BRIDGE_NAME);
__sync_fetch_and_sub(&tethering_enabled, 1);
- return;
+ return -EOPNOTSUPP;
}
prefixlen = connman_ipaddress_calc_netmask_len(subnet_mask);
@@ -441,7 +441,7 @@ void __connman_tethering_set_enabled(void)
__connman_ippool_unref(dhcp_ippool);
__connman_bridge_remove(BRIDGE_NAME);
__sync_fetch_and_sub(&tethering_enabled, 1);
- return;
+ return -EOPNOTSUPP;
}
err = __connman_ipv6pd_setup(BRIDGE_NAME);
@@ -450,6 +450,8 @@ void __connman_tethering_set_enabled(void)
strerror(-err));
DBG("tethering started");
+
+ return 0;
}
void __connman_tethering_set_disabled(void)
@@ -670,6 +672,8 @@ error:
close(fd);
g_free(iface);
g_free(path);
+ if (pn)
+ g_free(pn->owner);
g_free(pn);
return err;
}
diff --git a/src/timeserver.c b/src/timeserver.c
index fc83f9ae..6325eceb 100755
--- a/src/timeserver.c
+++ b/src/timeserver.c
@@ -305,6 +305,8 @@ static void ts_recheck_enable(void)
int __connman_timeserver_sync(struct connman_service *default_service)
{
struct connman_service *service;
+ char **nameservers;
+ int i;
if (default_service)
service = default_service;
@@ -328,6 +330,17 @@ int __connman_timeserver_sync(struct connman_service *default_service)
if (resolv_id > 0)
g_resolv_cancel_lookup(resolv, resolv_id);
+ g_resolv_flush_nameservers(resolv);
+
+ nameservers = connman_service_get_nameservers(service);
+ if (!nameservers)
+ return -EINVAL;
+
+ for (i = 0; nameservers[i]; i++)
+ g_resolv_add_nameserver(resolv, nameservers[i], 53, 0);
+
+ g_strfreev(nameservers);
+
g_slist_free_full(ts_list, g_free);
ts_list = __connman_timeserver_get_all(service);
diff --git a/src/util.c b/src/util.c
index da32cc55..732d4512 100755
--- a/src/util.c
+++ b/src/util.c
@@ -36,19 +36,24 @@
#define URANDOM "/dev/urandom"
-int f = -1;
+static int f = -1;
int __connman_util_get_random(uint64_t *val)
{
- int r = 0;
+ int r;
if (!val)
return -EINVAL;
- if (read(f, val, sizeof(uint64_t)) < 0) {
+ r = read(f, val, sizeof(uint64_t));
+ if (r < 0) {
r = -errno;
connman_warn_once("Could not read from "URANDOM);
*val = random();
+ } else if (r != sizeof(uint64_t)) {
+ r = -EIO;
+ connman_warn_once("Short read from "URANDOM);
+ *val = random();
}
return r;
@@ -58,7 +63,7 @@ int __connman_util_init(void)
{
int r = 0;
- if (f > 0)
+ if (f >= 0)
return 0;
f = open(URANDOM, O_RDONLY);
@@ -81,7 +86,7 @@ int __connman_util_init(void)
void __connman_util_cleanup(void)
{
- if (f > 0)
+ if (f >= 0)
close(f);
f = -1;
diff --git a/src/wispr.c b/src/wispr.c
index c3b0c9c9..adf62303 100755
--- a/src/wispr.c
+++ b/src/wispr.c
@@ -832,8 +832,8 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context)
int err = 0;
int i;
- DBG("wispr/portal context %p", wp_context);
- DBG("service %p", wp_context->service);
+ DBG("wispr/portal context %p service %p", wp_context,
+ wp_context->service);
service_type = connman_service_get_type(wp_context->service);
@@ -908,8 +908,7 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context)
free_connman_wispr_portal_context(wp_context);
}
} else if (wp_context->timeout == 0) {
- wp_context->timeout =
- g_timeout_add_seconds(0, no_proxy_callback, wp_context);
+ wp_context->timeout = g_idle_add(no_proxy_callback, wp_context);
}
done:
diff --git a/src/wpad.c b/src/wpad.c
index 109e9d71..b7f1f1e5 100755
--- a/src/wpad.c
+++ b/src/wpad.c
@@ -49,6 +49,8 @@ static void free_wpad(gpointer data)
{
struct connman_wpad *wpad = data;
+ connman_service_unref(wpad->service);
+
g_resolv_unref(wpad->resolv);
g_strfreev(wpad->addrlist);
@@ -152,7 +154,6 @@ int __connman_wpad_start(struct connman_service *service)
return -ENOMEM;
}
- wpad->service = service;
wpad->resolv = g_resolv_new(index);
if (!wpad->resolv) {
g_strfreev(nameservers);
@@ -174,10 +175,11 @@ int __connman_wpad_start(struct connman_service *service)
DBG("hostname %s", wpad->hostname);
+ wpad->service = connman_service_ref(service);
+
g_resolv_lookup_hostname(wpad->resolv, wpad->hostname,
wpad_result, wpad);
- connman_service_ref(service);
g_hash_table_replace(wpad_list, GINT_TO_POINTER(index), wpad);
return 0;
@@ -196,8 +198,7 @@ void __connman_wpad_stop(struct connman_service *service)
if (index < 0)
return;
- if (g_hash_table_remove(wpad_list, GINT_TO_POINTER(index)))
- connman_service_unref(service);
+ g_hash_table_remove(wpad_list, GINT_TO_POINTER(index));
}
int __connman_wpad_init(void)