summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNishant Chaprana <n.chaprana@samsung.com>2019-09-17 19:00:55 +0530
committerNishant Chaprana <n.chaprana@samsung.com>2019-09-18 19:23:41 +0530
commit26cc90dfaf2ad149b702626f9552c81abbb26862 (patch)
tree2524c8994cf58358350fde67dfba5c3b8cb58f7d /src
parent9e3beb21876b6e63bd8acf53e751480d7a1cc16f (diff)
parent6b2381a2adabea7d8309ff158ef675ff88184305 (diff)
downloadconnman-26cc90dfaf2ad149b702626f9552c81abbb26862.tar.gz
connman-26cc90dfaf2ad149b702626f9552c81abbb26862.tar.bz2
connman-26cc90dfaf2ad149b702626f9552c81abbb26862.zip
Imported Upstream version 1.37submit/tizen/20190920.082459
Change-Id: Idb47c1ddbedc9f97181b8e9a5eeac04ddd832a2c Signed-off-by: Nishant Chaprana <n.chaprana@samsung.com>
Diffstat (limited to 'src')
-rw-r--r--src/acd.c596
-rw-r--r--src/backtrace.c147
-rw-r--r--src/config.c43
-rwxr-xr-xsrc/connection.c18
-rw-r--r--src/connman-wait-online.service.in15
-rw-r--r--src/connman.h106
-rwxr-xr-xsrc/connman.service.in7
-rw-r--r--src/connman.socket1
-rw-r--r--src/connman_tv.service.in1
-rwxr-xr-xsrc/dbus.c29
-rw-r--r--src/device.c143
-rw-r--r--src/dhcp.c29
-rwxr-xr-xsrc/dhcpv6.c10
-rw-r--r--src/dns-systemd-resolved.c490
-rwxr-xr-xsrc/dnsproxy.c108
-rw-r--r--src/firewall-iptables.c62
-rw-r--r--src/firewall-nftables.c14
-rw-r--r--src/inet.c190
-rwxr-xr-xsrc/ipconfig.c3
-rwxr-xr-xsrc/ippool.c25
-rwxr-xr-xsrc/iptables.c2448
-rwxr-xr-xsrc/ipv6pd.c26
-rwxr-xr-xsrc/log.c118
-rw-r--r--src/main.c121
-rwxr-xr-xsrc/main.conf52
-rwxr-xr-xsrc/main_disable_eth.conf2
-rwxr-xr-xsrc/main_ivi.conf2
-rwxr-xr-xsrc/main_tv.conf2
-rw-r--r--src/manager.c46
-rwxr-xr-xsrc/nat.c6
-rwxr-xr-xsrc/network.c365
-rw-r--r--src/nostats.c60
-rw-r--r--src/notifier.c22
-rwxr-xr-xsrc/ntp.c258
-rwxr-xr-xsrc/peer.c17
-rwxr-xr-xsrc/provider.c6
-rwxr-xr-xsrc/resolver.c36
-rwxr-xr-xsrc/rfkill.c1
-rw-r--r--src/rtnl.c9
-rw-r--r--src/service.c1028
-rw-r--r--src/session.c75
-rw-r--r--src/shared/arp.c126
-rwxr-xr-xsrc/shared/arp.h47
-rwxr-xr-xsrc/stats.c7
-rwxr-xr-xsrc/storage.c2
-rw-r--r--src/technology.c99
-rwxr-xr-xsrc/tethering.c312
-rwxr-xr-xsrc/timeserver.c180
-rwxr-xr-xsrc/timezone.c1
-rwxr-xr-xsrc/util.c11
-rw-r--r--src/wispr.c2
-rwxr-xr-xsrc/wpad.c4
52 files changed, 5542 insertions, 1986 deletions
diff --git a/src/acd.c b/src/acd.c
new file mode 100644
index 00000000..7ace1554
--- /dev/null
+++ b/src/acd.c
@@ -0,0 +1,596 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2018 Commend International GmbH. 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.
+ *
+ */
+
+/*
+ * Address Conflict Detection (RFC 5227)
+ *
+ * based on DHCP client library with GLib integration,
+ * Copyright (C) 2009-2014 Intel Corporation. All rights reserved.
+ *
+ */
+
+#include <netinet/if_ether.h>
+#include <net/if_arp.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "connman.h"
+#include <connman/acd.h>
+#include <connman/log.h>
+#include <connman/inet.h>
+#include <connman/dbus.h>
+#include <glib.h>
+#include "src/shared/arp.h"
+
+enum acd_state {
+ ACD_STATE_PROBE,
+ ACD_STATE_ANNOUNCE,
+ ACD_STATE_MONITOR,
+ ACD_STATE_DEFEND,
+};
+
+static const char* acd_state_texts[] = {
+ "PROBE",
+ "ANNOUNCE",
+ "MONITOR",
+ "DEFEND"
+};
+
+struct acd_host {
+ enum acd_state state;
+ int ifindex;
+ char *interface;
+ uint8_t mac_address[6];
+ uint32_t requested_ip; /* host byte order */
+
+ /* address conflict fields */
+ uint32_t ac_ip; /* host byte order */
+ uint8_t ac_mac[6];
+ gint64 ac_timestamp;
+ bool ac_resolved;
+ const char *path;
+
+ bool listen_on;
+ int listener_sockfd;
+ unsigned int retry_times;
+ unsigned int conflicts;
+ guint timeout;
+ guint listener_watch;
+
+ acd_host_cb_t ipv4_available_cb;
+ gpointer ipv4_available_data;
+ acd_host_cb_t ipv4_lost_cb;
+ gpointer ipv4_lost_data;
+ acd_host_cb_t ipv4_conflict_cb;
+ gpointer ipv4_conflict_data;
+ acd_host_cb_t ipv4_max_conflicts_cb;
+ gpointer ipv4_max_conflicts_data;
+};
+
+static int start_listening(struct acd_host *acd);
+static void stop_listening(struct acd_host *acd);
+static gboolean acd_listener_event(GIOChannel *channel, GIOCondition condition,
+ gpointer acd_data);
+static int acd_recv_arp_packet(struct acd_host *acd);
+static void send_probe_packet(gpointer acd_data);
+static gboolean acd_probe_timeout(gpointer acd_data);
+static gboolean send_announce_packet(gpointer acd_data);
+static gboolean acd_announce_timeout(gpointer acd_data);
+static gboolean acd_defend_timeout(gpointer acd_data);
+
+/* for D-Bus property */
+static void report_conflict(struct acd_host *acd, const struct ether_arp* arp);
+
+static void debug(struct acd_host *acd, const char *format, ...)
+{
+ char str[256];
+ va_list ap;
+
+ va_start(ap, format);
+
+ if (vsnprintf(str, sizeof(str), format, ap) > 0)
+ connman_info("ACD index %d: %s", acd->ifindex, str);
+
+ va_end(ap);
+}
+
+void acd_host_free(struct acd_host *acd)
+{
+ if (!acd)
+ return;
+
+ g_free(acd->interface);
+ g_free(acd);
+}
+
+struct acd_host *acd_host_new(int ifindex, const char *path)
+{
+ struct acd_host *acd;
+
+ if (ifindex < 0) {
+ connman_error("Invalid interface index %d", ifindex);
+ return NULL;
+ }
+
+ acd = g_try_new0(struct acd_host, 1);
+ if (!acd) {
+ connman_error("Could not allocate ACD data structure");
+ return NULL;
+ }
+
+ acd->interface = connman_inet_ifname(ifindex);
+ if (!acd->interface) {
+ connman_error("Interface with index %d is not available", ifindex);
+ goto error;
+ }
+
+ if (!connman_inet_is_ifup(ifindex)) {
+ connman_error("Interface with index %d and name %s is down", ifindex,
+ acd->interface);
+ goto error;
+ }
+
+ __connman_inet_get_interface_mac_address(ifindex, acd->mac_address);
+
+ acd->listener_sockfd = -1;
+ acd->listen_on = false;
+ acd->ifindex = ifindex;
+ acd->listener_watch = 0;
+ acd->retry_times = 0;
+
+ acd->ipv4_available_cb = NULL;
+ acd->ipv4_lost_cb = NULL;
+ acd->ipv4_conflict_cb = NULL;
+ acd->ipv4_max_conflicts_cb = NULL;
+
+ acd->ac_ip = 0;
+ memset(acd->ac_mac, 0, sizeof(acd->ac_mac));
+ acd->ac_timestamp = 0;
+ acd->ac_resolved = true;
+ acd->path = path;
+
+ return acd;
+
+error:
+ acd_host_free(acd);
+ return NULL;
+}
+
+static void remove_timeout(struct acd_host *acd)
+{
+ if (acd->timeout > 0)
+ g_source_remove(acd->timeout);
+
+ acd->timeout = 0;
+}
+
+static int start_listening(struct acd_host *acd)
+{
+ GIOChannel *listener_channel;
+ int listener_sockfd;
+
+ if (acd->listen_on)
+ return 0;
+
+ debug(acd, "start listening");
+
+ listener_sockfd = arp_socket(acd->ifindex);
+ if (listener_sockfd < 0)
+ return -EIO;
+
+ listener_channel = g_io_channel_unix_new(listener_sockfd);
+ if (!listener_channel) {
+ /* Failed to create listener channel */
+ close(listener_sockfd);
+ return -EIO;
+ }
+
+ acd->listen_on = true;
+ acd->listener_sockfd = listener_sockfd;
+
+ g_io_channel_set_close_on_unref(listener_channel, TRUE);
+ acd->listener_watch =
+ g_io_add_watch_full(listener_channel, G_PRIORITY_HIGH,
+ G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
+ acd_listener_event, acd,
+ NULL);
+ g_io_channel_unref(listener_channel);
+
+ return 0;
+}
+
+static void stop_listening(struct acd_host *acd)
+{
+ if (!acd->listen_on)
+ return;
+
+ if (acd->listener_watch > 0)
+ g_source_remove(acd->listener_watch);
+ acd->listen_on = FALSE;
+ acd->listener_sockfd = -1;
+ acd->listener_watch = 0;
+}
+
+static gboolean acd_listener_event(GIOChannel *channel, GIOCondition condition,
+ gpointer acd_data)
+{
+ struct acd_host *acd = acd_data;
+
+ if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ acd->listener_watch = 0;
+ return FALSE;
+ }
+
+ if (!acd->listen_on)
+ return FALSE;
+
+ acd_recv_arp_packet(acd);
+
+ return TRUE;
+}
+
+static bool is_link_local(uint32_t ip)
+{
+ return (ip & LINKLOCAL_ADDR) == LINKLOCAL_ADDR;
+}
+
+static int acd_recv_arp_packet(struct acd_host *acd)
+{
+ ssize_t cnt;
+ struct ether_arp arp;
+ uint32_t ip_n; /* network byte order */
+ struct in_addr addr;
+ int source_conflict;
+ int target_conflict;
+ bool probe;
+ char* confltxt;
+ uint8_t* mac;
+ uint8_t* omac;
+
+ memset(&arp, 0, sizeof(arp));
+ cnt = read(acd->listener_sockfd, &arp, sizeof(arp));
+ if (cnt != sizeof(arp))
+ return -EINVAL;
+
+ if (arp.arp_op != htons(ARPOP_REPLY) &&
+ arp.arp_op != htons(ARPOP_REQUEST))
+ return -EINVAL;
+
+ if (memcmp(arp.arp_sha, acd->mac_address, ETH_ALEN) == 0)
+ return 0;
+
+ ip_n = htonl(acd->requested_ip);
+ source_conflict = !memcmp(arp.arp_spa, &ip_n, sizeof(uint32_t));
+ probe = !memcmp(arp.arp_spa, "\0\0\0\0", sizeof(uint32_t));
+ target_conflict = probe &&
+ !memcmp(arp.arp_tpa, &ip_n, sizeof(uint32_t));
+
+ if (!source_conflict && !target_conflict)
+ return 0;
+
+ acd->conflicts++;
+
+ confltxt = target_conflict ? "target" : "source";
+
+ addr.s_addr = ip_n;
+ debug(acd, "IPv4 %d %s conflicts detected for address %s. "
+ "State=%s", acd->conflicts, confltxt, inet_ntoa(addr),
+ acd_state_texts[acd->state]);
+ mac = acd->mac_address;
+ omac = arp.arp_sha;
+ debug(acd, "Our MAC: %02x:%02x:%02x:%02x:%02x:%02x"
+ " other MAC: %02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2],mac[3], mac[4], mac[5],
+ omac[0], omac[1], omac[2],omac[3], omac[4], omac[5]);
+
+ if (acd->state == ACD_STATE_MONITOR) {
+ if (!source_conflict)
+ return 0;
+
+ acd->state = ACD_STATE_DEFEND;
+ debug(acd, "DEFEND mode conflicts: %d", acd->conflicts);
+ /* Try to defend with a single announce. */
+ send_announce_packet(acd);
+ return 0;
+ } else if (acd->state == ACD_STATE_DEFEND) {
+ if (!source_conflict)
+ return 0;
+
+ debug(acd, "LOST IPv4 address %s", inet_ntoa(addr));
+ if (!is_link_local(acd->requested_ip))
+ report_conflict(acd, &arp);
+
+ if (acd->ipv4_lost_cb)
+ acd->ipv4_lost_cb(acd, acd->ipv4_lost_data);
+ return 0;
+ }
+
+ if (acd->conflicts < MAX_CONFLICTS) {
+ if (!is_link_local(acd->requested_ip))
+ report_conflict(acd, &arp);
+
+ acd_host_stop(acd);
+
+ /* we need a new request_ip */
+ if (acd->ipv4_conflict_cb)
+ acd->ipv4_conflict_cb(acd, acd->ipv4_conflict_data);
+ } else {
+ acd_host_stop(acd);
+
+ /*
+ * Here we got a lot of conflicts, RFC3927 and RFC5227 state that we
+ * have to wait RATE_LIMIT_INTERVAL before retrying.
+ */
+ if (acd->ipv4_max_conflicts_cb)
+ acd->ipv4_max_conflicts_cb(acd, acd->ipv4_max_conflicts_data);
+ }
+
+ return 0;
+}
+
+int acd_host_start(struct acd_host *acd, uint32_t ip)
+{
+ guint timeout;
+ int err;
+
+ remove_timeout(acd);
+
+ err = start_listening(acd);
+ if (err)
+ return err;
+
+ acd->retry_times = 0;
+ acd->requested_ip = ip;
+
+ /* First wait a random delay to avoid storm of ARP requests on boot */
+ timeout = __connman_util_random_delay_ms(PROBE_WAIT);
+ acd->state = ACD_STATE_PROBE;
+
+ acd->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
+ timeout,
+ acd_probe_timeout,
+ acd,
+ NULL);
+
+ return 0;
+}
+
+void acd_host_stop(struct acd_host *acd)
+{
+ stop_listening(acd);
+
+ remove_timeout(acd);
+
+ if (acd->listener_watch > 0) {
+ g_source_remove(acd->listener_watch);
+ acd->listener_watch = 0;
+ }
+
+ acd->state = ACD_STATE_PROBE;
+ acd->retry_times = 0;
+ acd->requested_ip = 0;
+}
+
+static void send_probe_packet(gpointer acd_data)
+{
+ guint timeout;
+ struct acd_host *acd = acd_data;
+
+ debug(acd, "sending ARP probe request");
+ remove_timeout(acd);
+ if (acd->retry_times == 1) {
+ acd->state = ACD_STATE_PROBE;
+ start_listening(acd);
+ }
+ arp_send_packet(acd->mac_address, 0,
+ acd->requested_ip, acd->ifindex);
+
+ if (acd->retry_times < PROBE_NUM) {
+ /* Add a random timeout in range of PROBE_MIN to PROBE_MAX. */
+ timeout = __connman_util_random_delay_ms(PROBE_MAX-PROBE_MIN);
+ timeout += PROBE_MIN * 1000;
+ } else
+ timeout = ANNOUNCE_WAIT * 1000;
+
+ acd->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
+ timeout,
+ acd_probe_timeout,
+ acd,
+ NULL);
+}
+
+static gboolean acd_probe_timeout(gpointer acd_data)
+{
+ struct acd_host *acd = acd_data;
+
+ acd->timeout = 0;
+
+ debug(acd, "acd probe timeout (retries %d)", acd->retry_times);
+ if (acd->retry_times == PROBE_NUM) {
+ acd->state = ACD_STATE_ANNOUNCE;
+ acd->retry_times = 1;
+
+ send_announce_packet(acd);
+ return FALSE;
+ }
+
+ acd->retry_times++;
+ send_probe_packet(acd);
+
+ return FALSE;
+}
+
+static gboolean send_announce_packet(gpointer acd_data)
+{
+ struct acd_host *acd = acd_data;
+
+ debug(acd, "sending ACD announce request");
+
+ arp_send_packet(acd->mac_address,
+ acd->requested_ip,
+ acd->requested_ip,
+ acd->ifindex);
+
+ remove_timeout(acd);
+
+ if (acd->state == ACD_STATE_DEFEND)
+ acd->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+ DEFEND_INTERVAL,
+ acd_defend_timeout,
+ acd,
+ NULL);
+ else
+ acd->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+ ANNOUNCE_INTERVAL,
+ acd_announce_timeout,
+ acd,
+ NULL);
+ return TRUE;
+}
+
+static gboolean acd_announce_timeout(gpointer acd_data)
+{
+ struct acd_host *acd = acd_data;
+
+ acd->timeout = 0;
+
+ debug(acd, "acd announce timeout (retries %d)", acd->retry_times);
+ if (acd->retry_times != ANNOUNCE_NUM) {
+ acd->retry_times++;
+ send_announce_packet(acd);
+ return FALSE;
+ }
+
+ debug(acd, "switching to monitor mode");
+ acd->state = ACD_STATE_MONITOR;
+
+ if (!acd->ac_resolved && !is_link_local(acd->requested_ip))
+ report_conflict(acd, NULL);
+
+ if (acd->ipv4_available_cb)
+ acd->ipv4_available_cb(acd,
+ acd->ipv4_available_data);
+ acd->conflicts = 0;
+
+ return FALSE;
+}
+
+static gboolean acd_defend_timeout(gpointer acd_data)
+{
+ struct acd_host *acd = acd_data;
+
+ debug(acd, "back to MONITOR mode");
+ acd->timeout = 0;
+ acd->conflicts = 0;
+ acd->state = ACD_STATE_MONITOR;
+
+ return FALSE;
+}
+
+void acd_host_register_event(struct acd_host *acd,
+ enum acd_host_event event,
+ acd_host_cb_t func,
+ gpointer user_data)
+{
+ switch (event) {
+ case ACD_HOST_EVENT_IPV4_AVAILABLE:
+ acd->ipv4_available_cb = func;
+ acd->ipv4_available_data = user_data;
+ break;
+ case ACD_HOST_EVENT_IPV4_LOST:
+ acd->ipv4_lost_cb = func;
+ acd->ipv4_lost_data = user_data;
+ break;
+ case ACD_HOST_EVENT_IPV4_CONFLICT:
+ acd->ipv4_conflict_cb = func;
+ acd->ipv4_conflict_data = user_data;
+ break;
+ case ACD_HOST_EVENT_IPV4_MAXCONFLICT:
+ acd->ipv4_max_conflicts_cb = func;
+ acd->ipv4_max_conflicts_data = user_data;
+ break;
+ default:
+ connman_warn("%s unknown event %d.", __FUNCTION__, event);
+ break;
+ }
+}
+
+static void append_ac_mac(DBusMessageIter *iter, void *user_data)
+{
+ struct acd_host *acd = user_data;
+ char mac[32];
+ uint8_t *m = acd->ac_mac;
+ const char *str = mac;
+
+ snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+ connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &str);
+}
+
+static void append_ac_ipv4(DBusMessageIter *iter, void *user_data)
+{
+ struct acd_host *acd = user_data;
+ struct in_addr addr;
+ char *a;
+
+ addr.s_addr = htonl(acd->ac_ip);
+ a = inet_ntoa(addr);
+ if (!a)
+ a = "";
+ connman_dbus_dict_append_basic(iter, "Address", DBUS_TYPE_STRING, &a);
+}
+
+static void append_ac_property(DBusMessageIter *iter, void *user_data)
+{
+ struct acd_host *acd = user_data;
+
+ connman_dbus_dict_append_dict(iter, "IPv4", append_ac_ipv4, acd);
+ connman_dbus_dict_append_dict(iter, "Ethernet", append_ac_mac, acd);
+ connman_dbus_dict_append_basic(iter, "Timestamp", DBUS_TYPE_INT64,
+ &acd->ac_timestamp);
+ connman_dbus_dict_append_basic(iter, "Resolved", DBUS_TYPE_BOOLEAN,
+ &acd->ac_resolved);
+}
+
+void acd_host_append_dbus_property(struct acd_host *acd, DBusMessageIter *dict)
+{
+ connman_dbus_dict_append_dict(dict, "LastAddressConflict",
+ append_ac_property, acd);
+}
+
+static void report_conflict(struct acd_host *acd, const struct ether_arp* arp)
+{
+ if (arp) {
+ acd->ac_ip = acd->requested_ip;
+ memcpy(acd->ac_mac, arp->arp_sha, sizeof(acd->ac_mac));
+ acd->ac_timestamp = g_get_real_time();
+ acd->ac_resolved = false;
+ } else {
+ acd->ac_resolved = true;
+ }
+
+ connman_dbus_property_changed_dict(acd->path, CONNMAN_SERVICE_INTERFACE,
+ "LastAddressConflict", append_ac_property, acd);
+}
+
+unsigned int acd_host_get_conflicts_count(struct acd_host *acd)
+{
+ return acd->conflicts;
+}
diff --git a/src/backtrace.c b/src/backtrace.c
new file mode 100644
index 00000000..bede6698
--- /dev/null
+++ b/src/backtrace.c
@@ -0,0 +1,147 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
+ * Copyright (C) 2016 Yann E. MORIN <yann.morin.1998@free.fr>. 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 <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <execinfo.h>
+#include <dlfcn.h>
+
+#include "connman.h"
+
+void print_backtrace(const char* program_path, const char* program_exec,
+ unsigned int offset)
+{
+ void *frames[99];
+ size_t n_ptrs;
+ unsigned int i;
+ int outfd[2], infd[2];
+ int pathlen;
+ pid_t pid;
+
+ if (!program_exec)
+ return;
+
+ pathlen = strlen(program_path);
+
+ n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
+ if (n_ptrs < offset)
+ return;
+
+ if (pipe(outfd) < 0)
+ return;
+
+ if (pipe(infd) < 0) {
+ close(outfd[0]);
+ close(outfd[1]);
+ return;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ close(outfd[0]);
+ close(outfd[1]);
+ close(infd[0]);
+ close(infd[1]);
+ return;
+ }
+
+ if (pid == 0) {
+ close(outfd[1]);
+ close(infd[0]);
+
+ dup2(outfd[0], STDIN_FILENO);
+ dup2(infd[1], STDOUT_FILENO);
+
+ execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
+
+ exit(EXIT_FAILURE);
+ }
+
+ close(outfd[0]);
+ close(infd[1]);
+
+ connman_error("++++++++ backtrace ++++++++");
+
+ for (i = offset; i < n_ptrs - 1; i++) {
+ Dl_info info;
+ char addr[20], buf[PATH_MAX * 2];
+ int len, written;
+ char *ptr, *pos;
+
+ dladdr(frames[i], &info);
+
+ len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
+ if (len < 0)
+ break;
+
+ written = write(outfd[1], addr, len);
+ if (written < 0)
+ break;
+
+ len = read(infd[0], buf, sizeof(buf) - 1);
+ if (len < 0)
+ break;
+
+ buf[len] = '\0';
+
+ pos = strchr(buf, '\n');
+ if (!pos) {
+ connman_error("Error in backtrace format");
+ break;
+ }
+
+ *pos++ = '\0';
+
+ if (strcmp(buf, "??") == 0) {
+ connman_error("#%-2u %p in %s", i - offset,
+ frames[i], info.dli_fname);
+ continue;
+ }
+
+ ptr = strchr(pos, '\n');
+ if (!ptr) {
+ connman_error("Error in backtrace format");
+ break;
+ }
+
+ *ptr++ = '\0';
+
+ if (strncmp(pos, program_path, pathlen) == 0)
+ pos += pathlen + 1;
+
+ connman_error("#%-2u %p in %s() at %s", i - offset,
+ frames[i], buf, pos);
+ }
+
+ connman_error("+++++++++++++++++++++++++++");
+
+ kill(pid, SIGTERM);
+
+ close(outfd[1]);
+ close(infd[0]);
+}
diff --git a/src/config.c b/src/config.c
index d4ba0b37..ca5957d6 100644
--- a/src/config.c
+++ b/src/config.c
@@ -72,6 +72,7 @@ struct connman_config_service {
char *ipv6_gateway;
char *ipv6_privacy;
char *mac;
+ bool mdns;
char **nameservers;
char **search_domains;
char **timeservers;
@@ -112,6 +113,7 @@ static bool cleanup = false;
#define SERVICE_KEY_PASSPHRASE "Passphrase"
#define SERVICE_KEY_SECURITY "Security"
#define SERVICE_KEY_HIDDEN "Hidden"
+#define SERVICE_KEY_MDNS "mDNS"
#define SERVICE_KEY_IPv4 "IPv4"
#define SERVICE_KEY_IPv6 "IPv6"
@@ -152,6 +154,7 @@ static const char *service_possible_keys[] = {
SERVICE_KEY_IPv6,
SERVICE_KEY_IPv6_PRIVACY,
SERVICE_KEY_MAC,
+ SERVICE_KEY_MDNS,
SERVICE_KEY_NAMESERVERS,
SERVICE_KEY_SEARCH_DOMAINS,
SERVICE_KEY_TIMESERVERS,
@@ -193,7 +196,7 @@ static void unregister_service(gpointer data)
list = list->next) {
service_id = list->data;
- service = __connman_service_lookup_from_ident(service_id);
+ service = connman_service_lookup_from_identifier(service_id);
if (service) {
__connman_service_set_immutable(service, false);
__connman_service_set_config(service, NULL, NULL);
@@ -514,6 +517,9 @@ static bool load_service_generic(GKeyFile *keyfile,
g_strfreev(strlist);
}
+ service->mdns = __connman_config_get_bool(keyfile, group,
+ SERVICE_KEY_MDNS, NULL);
+
return true;
err:
@@ -564,8 +570,8 @@ static bool load_service(GKeyFile *keyfile, const char *group,
g_free(service->type);
service->type = str;
} else {
- DBG("Type of the configured service is missing for group %s",
- group);
+ connman_warn("Type of the configured service is missing "
+ "for group %s", group);
goto err;
}
@@ -759,14 +765,14 @@ static bool load_service(GKeyFile *keyfile, const char *group,
service->security = CONNMAN_SERVICE_SECURITY_PSK;
} else if (str) {
- if (security != CONNMAN_SERVICE_SECURITY_NONE) {
+ 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;
+
+ service->security = CONNMAN_SERVICE_SECURITY_NONE;
} else
- service->security = CONNMAN_SERVICE_SECURITY_NONE;
+ service->security = CONNMAN_SERVICE_SECURITY_NONE;
g_free(str);
@@ -806,8 +812,11 @@ static bool load_service_from_keyfile(GKeyFile *keyfile,
groups = g_key_file_get_groups(keyfile, NULL);
for (i = 0; groups[i]; i++) {
- if (!g_str_has_prefix(groups[i], "service_"))
+ if (!g_str_has_prefix(groups[i], "service_")) {
+ connman_warn("Ignore group named '%s' because prefix "
+ "is not 'service_'", groups[i]);
continue;
+ }
if (load_service(keyfile, groups[i], config))
found = true;
}
@@ -1211,6 +1220,7 @@ static int try_provision_service(struct connman_config_service *config,
enum connman_service_type type;
const void *ssid;
unsigned int ssid_len;
+ const char *str;
network = __connman_service_get_network(service);
if (!network) {
@@ -1230,10 +1240,8 @@ static int try_provision_service(struct connman_config_service *config,
ssid = connman_network_get_blob(network, "WiFi.SSID",
&ssid_len);
- if (!ssid) {
- connman_error("Network SSID not set");
- return -EINVAL;
- }
+ if (!ssid)
+ return -ENOENT;
if (!config->ssid || ssid_len != config->ssid_len)
return -ENOENT;
@@ -1241,6 +1249,10 @@ static int try_provision_service(struct connman_config_service *config,
if (memcmp(config->ssid, ssid, ssid_len))
return -ENOENT;
+ str = connman_network_get_string(network, "WiFi.Security");
+ if (config->security != __connman_service_string2security(str))
+ return -ENOENT;
+
break;
case CONNMAN_SERVICE_TYPE_ETHERNET:
@@ -1266,7 +1278,7 @@ static int try_provision_service(struct connman_config_service *config,
}
DBG("service %p ident %s", service,
- __connman_service_get_ident(service));
+ connman_service_get_identifier(service));
if (config->mac) {
struct connman_device *device;
@@ -1387,7 +1399,7 @@ ipv4_out:
#endif
__connman_service_disconnect(service);
- service_id = __connman_service_get_ident(service);
+ service_id = connman_service_get_identifier(service);
config->service_identifiers =
g_slist_prepend(config->service_identifiers,
g_strdup(service_id));
@@ -1426,6 +1438,8 @@ ipv4_out:
__connman_service_set_search_domains(service,
config->search_domains);
+ __connman_service_set_mdns(service, config->mdns);
+
if (config->timeservers)
__connman_service_set_timeservers(service,
config->timeservers);
@@ -1752,7 +1766,6 @@ void connman_config_free_entries(struct connman_config_entry **entries)
}
g_free(entries);
- return;
}
bool __connman_config_address_provisioned(const char *address,
diff --git a/src/connection.c b/src/connection.c
index 64d48b7d..f8194a64 100755
--- a/src/connection.c
+++ b/src/connection.c
@@ -460,6 +460,7 @@ static void set_default_gateway(struct gateway_data *data,
"0.0.0.0") == 0) {
if (connman_inet_set_gateway_interface(index) < 0)
return;
+ data->ipv4_gateway->active = true;
goto done;
}
@@ -468,6 +469,7 @@ static void set_default_gateway(struct gateway_data *data,
"::") == 0) {
if (connman_inet_set_ipv6_gateway_interface(index) < 0)
return;
+ data->ipv6_gateway->active = true;
goto done;
}
@@ -534,6 +536,7 @@ static void unset_default_gateway(struct gateway_data *data,
g_strcmp0(data->ipv4_gateway->gateway,
"0.0.0.0") == 0) {
connman_inet_clear_gateway_interface(index);
+ data->ipv4_gateway->active = false;
return;
}
@@ -541,6 +544,7 @@ static void unset_default_gateway(struct gateway_data *data,
g_strcmp0(data->ipv6_gateway->gateway,
"::") == 0) {
connman_inet_clear_ipv6_gateway_interface(index);
+ data->ipv6_gateway->active = false;
return;
}
@@ -557,7 +561,7 @@ static struct gateway_data *find_default_gateway(void)
{
struct connman_service *service;
- service = __connman_service_get_default();
+ service = connman_service_get_default();
if (!service)
return NULL;
@@ -1078,12 +1082,18 @@ bool __connman_connection_update_gateway(void)
old_default = default_gateway;
}
#endif
- if (updated && default_gateway) {
- if (default_gateway->ipv4_gateway)
+ /*
+ * Set default gateway if it has been updated or if it has not been
+ * set as active yet.
+ */
+ if (default_gateway) {
+ if (default_gateway->ipv4_gateway &&
+ (updated || !default_gateway->ipv4_gateway->active))
set_default_gateway(default_gateway,
CONNMAN_IPCONFIG_TYPE_IPV4);
- if (default_gateway->ipv6_gateway)
+ if (default_gateway->ipv6_gateway &&
+ (updated || !default_gateway->ipv6_gateway->active))
set_default_gateway(default_gateway,
CONNMAN_IPCONFIG_TYPE_IPV6);
}
diff --git a/src/connman-wait-online.service.in b/src/connman-wait-online.service.in
new file mode 100644
index 00000000..c2ad5cc9
--- /dev/null
+++ b/src/connman-wait-online.service.in
@@ -0,0 +1,15 @@
+[Unit]
+Description=Wait for network to be configured by ConnMan
+Requisite=connman.service
+After=connman.service
+Before=network-online.target
+DefaultDependencies=no
+Conflicts=shutdown.target
+
+[Service]
+Type=oneshot
+ExecStart=@sbindir@/connmand-wait-online
+RemainAfterExit=yes
+
+[Install]
+WantedBy=network-online.target
diff --git a/src/connman.h b/src/connman.h
index bb4c0e59..57c30508 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -133,6 +133,7 @@ int __connman_agent_request_peer_authorization(struct connman_peer *peer,
bool wps_requested,
const char *dbus_sender,
void *user_data);
+
#include <connman/log.h>
int __connman_log_init(const char *program, const char *debug,
@@ -142,6 +143,8 @@ void __connman_log_cleanup(gboolean backtrace);
void __connman_log_enable(struct connman_debug_desc *start,
struct connman_debug_desc *stop);
+#include <connman/backtrace.h>
+
#include <connman/option.h>
#include <connman/setting.h>
@@ -166,6 +169,9 @@ int __connman_inet_modify_address(int cmd, int flags, int index, int family,
const char *broadcast);
int __connman_inet_get_interface_address(int index, int family, void *address);
int __connman_inet_get_interface_ll_address(int index, int family, void *address);
+int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address);
+
+bool __connman_inet_is_any_addr(const char *address, int family);
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
@@ -248,7 +254,11 @@ int __connman_inet_rtnl_addattr32(struct nlmsghdr *n, size_t maxlen,
int __connman_inet_add_fwmark_rule(uint32_t table_id, int family, uint32_t fwmark);
int __connman_inet_del_fwmark_rule(uint32_t table_id, int family, uint32_t fwmark);
int __connman_inet_add_default_to_table(uint32_t table_id, int ifindex, const char *gateway);
+int __connman_inet_add_subnet_to_table(uint32_t table_id, int ifindex,
+ const char *gateway, unsigned char prefixlen);
int __connman_inet_del_default_from_table(uint32_t table_id, int ifindex, const char *gateway);
+int __connman_inet_del_subnet_from_table(uint32_t table_id, int ifindex,
+ const char *gateway, unsigned char prefixlen);
int __connman_inet_get_address_netmask(int ifindex,
struct sockaddr_in *address, struct sockaddr_in *netmask);
@@ -263,6 +273,7 @@ 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);
+int __connman_resolver_set_mdns(int index, bool enabled);
GKeyFile *__connman_storage_open_global(void);
GKeyFile *__connman_storage_load_global(void);
@@ -464,7 +475,6 @@ GSList *__connman_timeserver_add_list(GSList *server_list,
const char *timeserver);
GSList *__connman_timeserver_get_all(struct connman_service *service);
int __connman_timeserver_sync(struct connman_service *service);
-void __connman_timeserver_sync_next();
enum __connman_dhcpv6_status {
CONNMAN_DHCPV6_STATUS_FAIL = 0,
@@ -488,6 +498,7 @@ int __connman_dhcp_start(struct connman_ipconfig *ipconfig,
struct connman_network *network, dhcp_cb callback,
gpointer user_data);
void __connman_dhcp_stop(struct connman_ipconfig *ipconfig);
+void __connman_dhcp_decline(struct connman_ipconfig *ipconfig);
int __connman_dhcp_init(void);
void __connman_dhcp_cleanup(void);
int __connman_dhcpv6_init(void);
@@ -524,7 +535,9 @@ int __connman_connection_get_vpn_index(int phy_index);
bool __connman_connection_update_gateway(void);
-int __connman_ntp_start(char *server);
+typedef void (*__connman_ntp_cb_t) (bool success, void *user_data);
+int __connman_ntp_start(char *server, __connman_ntp_cb_t callback,
+ void *user_data);
void __connman_ntp_stop();
int __connman_wpad_init(void);
@@ -593,10 +606,12 @@ void __connman_device_list(DBusMessageIter *iter, void *user_data);
enum connman_service_type __connman_device_get_service_type(struct connman_device *device);
struct connman_device *__connman_device_find_device(enum connman_service_type type);
int __connman_device_request_scan(enum connman_service_type type);
+int __connman_device_request_scan_full(enum connman_service_type type);
int __connman_device_request_hidden_scan(struct connman_device *device,
const char *ssid, unsigned int ssid_len,
const char *identity, const char *passphrase,
const char *security, void *user_data);
+void __connman_device_stop_scan(enum connman_service_type type);
#if defined TIZEN_EXT
int __connman_device_request_specific_scan(enum connman_service_type type,
int scan_type, GSList *specific_scan_list);
@@ -665,12 +680,15 @@ bool __connman_config_get_bool(GKeyFile *key_file,
bool __connman_config_address_provisioned(const char *address,
const char *netmask);
+#include <connman/tethering.h>
+
int __connman_tethering_init(void);
void __connman_tethering_cleanup(void);
const char *__connman_tethering_get_bridge(void);
int __connman_tethering_set_enabled(void);
void __connman_tethering_set_disabled(void);
+void __connman_tethering_list_clients(DBusMessageIter *array);
int __connman_private_network_request(DBusMessage *msg, const char *owner);
int __connman_private_network_release(const char *path);
@@ -719,11 +737,9 @@ 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);
struct connman_service *__connman_service_create_from_provider(struct connman_provider *provider);
bool __connman_service_index_is_default(int index);
-struct connman_service *__connman_service_get_default(void);
#if defined TIZEN_EXT
void __connman_service_notify_strength_changed(struct connman_network *network);
#endif
@@ -740,13 +756,12 @@ struct connman_ipconfig *__connman_service_get_ipconfig(
struct connman_service *service, int family);
void __connman_service_notify_ipv4_configuration(
struct connman_service *service);
+void __connman_service_wispr_start(struct connman_service *service,
+ enum connman_ipconfig_type type);
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);
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);
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);
@@ -766,6 +781,8 @@ int __connman_service_set_ignore(struct connman_service *service,
bool ignore);
void __connman_service_set_search_domains(struct connman_service *service,
char **domains);
+int __connman_service_set_mdns(struct connman_service *service,
+ bool enabled);
void __connman_service_set_string(struct connman_service *service,
const char *key, const char *value);
@@ -898,9 +915,6 @@ void __connman_service_notify(struct connman_service *service,
unsigned int rx_error, unsigned int tx_error,
unsigned int rx_dropped, unsigned int tx_dropped);
-bool __connman_service_is_user_allowed(enum connman_service_type type,
- uid_t uid);
-
int __connman_service_counter_register(const char *counter);
void __connman_service_counter_unregister(const char *counter);
@@ -911,6 +925,7 @@ void __connman_peer_cleanup(void);
void __connman_peer_list_struct(DBusMessageIter *array);
const char *__connman_peer_get_path(struct connman_peer *peer);
+void __connman_peer_disconnect_all(void);
int __connman_peer_service_init(void);
void __connman_peer_service_cleanup(void);
@@ -954,11 +969,6 @@ void __connman_mesh_auto_connect(void);
#include <connman/session.h>
-typedef void (* service_iterate_cb) (struct connman_service *service,
- void *user_data);
-
-int __connman_service_iterate_services(service_iterate_cb cb, void *user_data);
-
void __connman_service_mark_dirty();
void __connman_service_save(struct connman_service *service);
@@ -1040,35 +1050,47 @@ int __connman_stats_get(struct connman_service *service,
bool roaming,
struct connman_stats_data *data);
-int __connman_iptables_dump(const char *table_name);
-int __connman_iptables_new_chain(const char *table_name,
- const char *chain);
-int __connman_iptables_delete_chain(const char *table_name,
- const char *chain);
-int __connman_iptables_flush_chain(const char *table_name,
- const char *chain);
-int __connman_iptables_change_policy(const char *table_name,
- const char *chain,
- const char *policy);
-int __connman_iptables_append(const char *table_name,
- const char *chain,
- const char *rule_spec);
-int __connman_iptables_insert(const char *table_name,
- const char *chain,
- const char *rule_spec);
-int __connman_iptables_delete(const char *table_name,
- const char *chain,
- const char *rule_spec);
+int __connman_iptables_dump(int type,
+ const char *table_name);
+int __connman_iptables_new_chain(int type,
+ const char *table_name,
+ const char *chain);
+int __connman_iptables_delete_chain(int type,
+ const char *table_name,
+ const char *chain);
+int __connman_iptables_flush_chain(int type,
+ const char *table_name,
+ const char *chain);
+int __connman_iptables_find_chain(int type,
+ const char *table_name,
+ const char *chain);
+int __connman_iptables_change_policy(int type,
+ const char *table_name,
+ const char *chain,
+ const char *policy);
+int __connman_iptables_append(int type,
+ const char *table_name,
+ const char *chain,
+ const char *rule_spec);
+int __connman_iptables_insert(int type,
+ const char *table_name,
+ const char *chain,
+ const char *rule_spec);
+int __connman_iptables_delete(int type,
+ const char *table_name,
+ const char *chain,
+ const char *rule_spec);
typedef void (*connman_iptables_iterate_chains_cb_t) (const char *chain_name,
void *user_data);
-int __connman_iptables_iterate_chains(const char *table_name,
+int __connman_iptables_iterate_chains(int type,
+ const char *table_name,
connman_iptables_iterate_chains_cb_t cb,
void *user_data);
int __connman_iptables_init(void);
void __connman_iptables_cleanup(void);
-int __connman_iptables_commit(const char *table_name);
+int __connman_iptables_commit(int type, const char *table_name);
int __connman_dnsproxy_init(void);
void __connman_dnsproxy_cleanup(void);
@@ -1076,6 +1098,7 @@ int __connman_dnsproxy_add_listener(int index);
void __connman_dnsproxy_remove_listener(int index);
int __connman_dnsproxy_append(int index, const char *domain, const char *server);
int __connman_dnsproxy_remove(int index, const char *domain, const char *server);
+int __connman_dnsproxy_set_mdns(int index, bool enabled);
int __connman_6to4_probe(struct connman_service *service);
void __connman_6to4_remove(struct connman_ipconfig *ipconfig);
@@ -1089,15 +1112,7 @@ typedef void (*ippool_collision_cb_t) (struct connman_ippool *pool,
int __connman_ippool_init(void);
void __connman_ippool_cleanup(void);
-#define __connman_ippool_ref(ipconfig) \
- __connman_ippool_ref_debug(ipconfig, __FILE__, __LINE__, __func__)
-#define __connman_ippool_unref(ipconfig) \
- __connman_ippool_unref_debug(ipconfig, __FILE__, __LINE__, __func__)
-
-struct connman_ippool *__connman_ippool_ref_debug(struct connman_ippool *pool,
- const char *file, int line, const char *caller);
-void __connman_ippool_unref_debug(struct connman_ippool *pool,
- const char *file, int line, const char *caller);
+void __connman_ippool_free(struct connman_ippool *pool);
struct connman_ippool *__connman_ippool_create(int index,
unsigned int start,
@@ -1188,6 +1203,7 @@ int __connman_machine_init(void);
void __connman_machine_cleanup(void);
int __connman_util_get_random(uint64_t *val);
+unsigned int __connman_util_random_delay_ms(unsigned int secs);
int __connman_util_init(void);
void __connman_util_cleanup(void);
diff --git a/src/connman.service.in b/src/connman.service.in
index 31febbde..a1ddddc7 100755
--- a/src/connman.service.in
+++ b/src/connman.service.in
@@ -1,6 +1,11 @@
[Unit]
Description=Connection service
-After=net-config.service
+DefaultDependencies=false
+Conflicts=shutdown.target
+RequiresMountsFor=@localstatedir@/lib/connman
+After=dbus.service network-pre.target systemd-sysusers.service net-config.service
+Before=network.target multi-user.target shutdown.target
+Wants=network.target
[Service]
Type=dbus
diff --git a/src/connman.socket b/src/connman.socket
index bcf8638e..3e1e64d5 100644
--- a/src/connman.socket
+++ b/src/connman.socket
@@ -1,5 +1,6 @@
[Unit]
Description=DNS Proxy Socket
+Before=connman.service
[Socket]
ListenStream=127.0.0.1:53
diff --git a/src/connman_tv.service.in b/src/connman_tv.service.in
index e5faac27..9eb75b24 100644
--- a/src/connman_tv.service.in
+++ b/src/connman_tv.service.in
@@ -1,6 +1,7 @@
[Unit]
Description=Connection service
After=net-config.service
+DefaultDependencies=no
[Service]
Type=dbus
diff --git a/src/dbus.c b/src/dbus.c
index 71728300..d80a46ce 100755
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -524,35 +524,6 @@ err:
return err;
}
-int connman_dbus_get_connection_unix_user_sync(DBusConnection *connection,
- const char *bus_name,
- unsigned int *user_id)
-{
-#if defined TIZEN_EXT
- *user_id = 0;
-#else
- unsigned long uid;
- DBusError err;
-
- dbus_error_init(&err);
-
- uid = dbus_bus_get_unix_user(connection, bus_name, &err);
-
- if (uid == (unsigned long)-1) {
- DBG("Can not get unix user ID!");
- if (dbus_error_is_set(&err)) {
- DBG("%s", err.message);
- dbus_error_free(&err);
- }
- return -1;
- }
-
- *user_id = (unsigned int)uid;
-#endif
-
- return 0;
-}
-
static unsigned char *parse_context(DBusMessage *msg)
{
DBusMessageIter iter, array;
diff --git a/src/device.c b/src/device.c
index 8b77021a..df7b2bbc 100644
--- a/src/device.c
+++ b/src/device.c
@@ -52,7 +52,7 @@ struct connman_device {
* request
*/
bool powered;
- bool scanning;
+ bool scanning[MAX_CONNMAN_SERVICE_TYPES];
char *name;
char *node;
char *address;
@@ -152,6 +152,33 @@ enum connman_service_type __connman_device_get_service_type(
return CONNMAN_SERVICE_TYPE_UNKNOWN;
}
+static bool device_has_service_type(struct connman_device *device,
+ enum connman_service_type service_type)
+{
+ enum connman_service_type device_service_type =
+ __connman_device_get_service_type(device);
+
+ /*
+ * For devices whose device_service_type is unknown we should
+ * allow to decide whether they support specific service_type
+ * by themself.
+ */
+ if (device_service_type == CONNMAN_SERVICE_TYPE_UNKNOWN)
+ return true;
+
+#if defined TIZEN_EXT_WIFI_MESH
+ if (device_service_type == CONNMAN_SERVICE_TYPE_MESH)
+ return service_type != CONNMAN_SERVICE_TYPE_MESH;
+#endif
+
+ if (device_service_type == CONNMAN_SERVICE_TYPE_WIFI) {
+ return service_type == CONNMAN_SERVICE_TYPE_WIFI ||
+ service_type == CONNMAN_SERVICE_TYPE_P2P;
+ }
+
+ return service_type == device_service_type;
+}
+
static gboolean device_pending_reset(gpointer user_data)
{
struct connman_device *device = user_data;
@@ -179,7 +206,7 @@ int __connman_device_enable(struct connman_device *device)
return -EBUSY;
if (device->powered_pending == PENDING_ENABLE)
- return -EALREADY;
+ return -EINPROGRESS;
if (device->powered_pending == PENDING_NONE && device->powered)
return -EALREADY;
@@ -230,7 +257,7 @@ int __connman_device_disable(struct connman_device *device)
return -EBUSY;
if (device->powered_pending == PENDING_DISABLE)
- return -EALREADY;
+ return -EINPROGRESS;
if (device->powered_pending == PENDING_NONE && !device->powered)
return -EALREADY;
@@ -565,7 +592,9 @@ const char *connman_device_get_ident(struct connman_device *device)
int connman_device_set_powered(struct connman_device *device,
bool powered)
{
+ struct connman_device_scan_params params;
enum connman_service_type type;
+ int i;
DBG("device %p powered %d", device, powered);
@@ -587,11 +616,15 @@ int connman_device_set_powered(struct connman_device *device,
__connman_technology_enabled(type);
- device->scanning = false;
+ for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
+ device->scanning[i] = false;
+
+ if (device->driver && device->driver->scan) {
+ memset(&params, 0, sizeof(params));
+ params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
- if (device->driver && device->driver->scan)
- device->driver->scan(CONNMAN_SERVICE_TYPE_UNKNOWN, device,
- NULL, 0, NULL, NULL, NULL, NULL);
+ device->driver->scan(device, &params);
+ }
return 0;
}
@@ -602,16 +635,22 @@ bool connman_device_get_powered(struct connman_device *device)
}
static int device_scan(enum connman_service_type type,
- struct connman_device *device)
+ struct connman_device *device,
+ bool force_full_scan)
{
+ struct connman_device_scan_params params;
+
if (!device->driver || !device->driver->scan)
return -EOPNOTSUPP;
if (!device->powered)
return -ENOLINK;
- return device->driver->scan(type, device, NULL, 0,
- NULL, NULL, NULL, NULL);
+ memset(&params, 0, sizeof(params));
+ params.type = type;
+ params.force_full_scan = force_full_scan;
+
+ return device->driver->scan(device, &params);
}
int __connman_device_disconnect(struct connman_device *device)
@@ -682,7 +721,8 @@ static gboolean remove_unavailable_network(gpointer key, gpointer value,
{
struct connman_network *network = value;
- if (connman_network_get_connected(network))
+ if (connman_network_get_connected(network) ||
+ connman_network_get_connecting(network))
return FALSE;
if (connman_network_get_available(network))
@@ -697,9 +737,19 @@ void __connman_device_cleanup_networks(struct connman_device *device)
remove_unavailable_network, NULL);
}
-bool connman_device_get_scanning(struct connman_device *device)
+bool connman_device_get_scanning(struct connman_device *device,
+ enum connman_service_type type)
{
- return device->scanning;
+ int i;
+
+ if (type != CONNMAN_SERVICE_TYPE_UNKNOWN)
+ return device->scanning[type];
+
+ for (i = 0; i < MAX_CONNMAN_SERVICE_TYPES; i++)
+ if (device->scanning[i])
+ return true;
+
+ return false;
}
void connman_device_reset_scanning(struct connman_device *device)
@@ -723,10 +773,13 @@ int connman_device_set_scanning(struct connman_device *device,
if (!device->driver || !device->driver->scan)
return -EINVAL;
- if (device->scanning == scanning)
+ if (type == CONNMAN_SERVICE_TYPE_UNKNOWN)
+ return -EINVAL;
+
+ if (device->scanning[type] == scanning)
return -EALREADY;
- device->scanning = scanning;
+ device->scanning[type] = scanning;
if (scanning) {
__connman_technology_scan_started(device);
@@ -1211,7 +1264,8 @@ int __connman_device_request_mesh_specific_scan(enum connman_service_type type,
#endif /* TIZEN_EXT_WIFI_MESH */
#endif
-int __connman_device_request_scan(enum connman_service_type type)
+static int connman_device_request_scan(enum connman_service_type type,
+ bool force_full_scan)
{
bool success = false;
int last_err = -ENOSYS;
@@ -1238,23 +1292,11 @@ int __connman_device_request_scan(enum connman_service_type type)
for (list = device_list; list; list = list->next) {
struct connman_device *device = list->data;
- enum connman_service_type service_type =
- __connman_device_get_service_type(device);
- if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) {
- if (type == CONNMAN_SERVICE_TYPE_P2P) {
- if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
- continue;
-#if defined TIZEN_EXT_WIFI_MESH
- } else if (type == CONNMAN_SERVICE_TYPE_MESH) {
- if (service_type != CONNMAN_SERVICE_TYPE_WIFI)
- continue;
-#endif
- } else if (service_type != type)
- continue;
- }
+ if (!device_has_service_type(device, type))
+ continue;
- err = device_scan(type, device);
+ err = device_scan(type, device, force_full_scan);
#if defined TIZEN_EXT
/* When Scan is already in progress then return Error so that
* wifi-manager can block the scan-done signal to be sent to
@@ -1277,20 +1319,53 @@ int __connman_device_request_scan(enum connman_service_type type)
return last_err;
}
+int __connman_device_request_scan(enum connman_service_type type)
+{
+ return connman_device_request_scan(type, false);
+}
+
+int __connman_device_request_scan_full(enum connman_service_type type)
+{
+ return connman_device_request_scan(type, true);
+}
+
int __connman_device_request_hidden_scan(struct connman_device *device,
const char *ssid, unsigned int ssid_len,
const char *identity, const char *passphrase,
const char *security, void *user_data)
{
+ struct connman_device_scan_params params;
+
DBG("device %p", device);
if (!device || !device->driver ||
!device->driver->scan)
return -EINVAL;
- return device->driver->scan(CONNMAN_SERVICE_TYPE_UNKNOWN,
- device, ssid, ssid_len, identity,
- passphrase, security, user_data);
+ params.type = CONNMAN_SERVICE_TYPE_UNKNOWN;
+ params.ssid = ssid;
+ params.ssid_len = ssid_len;
+ params.identity = identity;
+ params.passphrase = passphrase;
+ params.security = security;
+ params.user_data = user_data;
+
+ return device->driver->scan(device, &params);
+}
+
+void __connman_device_stop_scan(enum connman_service_type type)
+{
+ GSList *list;
+
+ for (list = device_list; list; list = list->next) {
+ struct connman_device *device = list->data;
+
+ if (!device_has_service_type(device, type))
+ continue;
+
+ if (device->driver && device->driver->stop_scan)
+ device->driver->stop_scan(type, device);
+ }
}
#if defined TIZEN_EXT
diff --git a/src/dhcp.c b/src/dhcp.c
index 26a350be..16f59b74 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -134,7 +134,7 @@ static bool apply_dhcp_invalidate_on_network(struct connman_dhcp *dhcp)
CONNMAN_IPCONFIG_TYPE_IPV4);
#else
__connman_service_nameserver_remove(service,
- dhcp->nameservers[i], false);
+ dhcp->nameservers[i], false);
#endif
}
g_strfreev(dhcp->nameservers);
@@ -265,6 +265,7 @@ static gboolean dhcp_retry_cb(gpointer user_data)
struct connman_dhcp *dhcp = user_data;
dhcp->timeout = 0;
+
#if defined TIZEN_EXT
DBG("dhcp %p", dhcp);
DBG("dhcp->timeout %d", dhcp->timeout);
@@ -849,6 +850,30 @@ void __connman_dhcp_stop(struct connman_ipconfig *ipconfig)
}
}
+void __connman_dhcp_decline(struct connman_ipconfig *ipconfig)
+{
+ struct connman_dhcp *dhcp;
+ const char *address;
+ struct in_addr addr;
+
+ DBG("ipconfig_table %p ipconfig %p", ipconfig_table, ipconfig);
+
+ if (!ipconfig_table)
+ return;
+
+ dhcp = g_hash_table_lookup(ipconfig_table, ipconfig);
+ if (dhcp) {
+ address = __connman_ipconfig_get_local(ipconfig);
+ if (!address)
+ return;
+
+ if (inet_pton(AF_INET, address, &addr) != 1)
+ connman_error("Could not convert address %s", address);
+
+ g_dhcp_client_decline(dhcp->dhcp_client, htonl(addr.s_addr));
+ }
+}
+
int __connman_dhcp_init(void)
{
DBG("");
@@ -865,6 +890,4 @@ void __connman_dhcp_cleanup(void)
g_hash_table_destroy(ipconfig_table);
ipconfig_table = NULL;
-
- dhcp_cleanup_random();
}
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index c624cb00..4c07c769 100755
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -196,7 +196,7 @@ static int set_duid(struct connman_service *service,
unsigned char *duid;
int duid_len;
- ident = __connman_service_get_ident(service);
+ ident = connman_service_get_identifier(service);
#if defined TIZEN_EXT
if(ident != NULL)
DBG("ident : %s", ident);
@@ -342,8 +342,8 @@ static void info_req_cb(GDHCPClient *dhcp_client, gpointer user_data)
CONNMAN_IPCONFIG_TYPE_IPV6);
#else
__connman_service_nameserver_remove(service,
- dhcp->nameservers[i],
- false);
+ dhcp->nameservers[i],
+ false);
#endif
#if defined TIZEN_EXT
}
@@ -579,8 +579,8 @@ static int set_other_addresses(GDHCPClient *dhcp_client,
false, CONNMAN_IPCONFIG_TYPE_IPV6);
#else
__connman_service_nameserver_append(service,
- dhcp->nameservers[i],
- false);
+ dhcp->nameservers[i],
+ false);
#endif
#if defined TIZEN_EXT
}
diff --git a/src/dns-systemd-resolved.c b/src/dns-systemd-resolved.c
new file mode 100644
index 00000000..5fe306c3
--- /dev/null
+++ b/src/dns-systemd-resolved.c
@@ -0,0 +1,490 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2017 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 <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <gdbus.h>
+#include <glib.h>
+#include <connman/dbus.h>
+
+#include "connman.h"
+
+#define SYSTEMD_RESOLVED_SERVICE "org.freedesktop.resolve1"
+#define SYSTEMD_RESOLVED_PATH "/org/freedesktop/resolve1"
+
+struct mdns_data {
+ int index;
+ bool enabled;
+};
+
+static GHashTable *interface_hash;
+static DBusConnection *connection;
+static GDBusClient *client;
+static GDBusProxy *resolved_proxy;
+
+/* update after a full set of instructions has been received */
+static guint update_interfaces_source;
+
+struct dns_interface {
+ GList *domains;
+ GList *servers;
+ int index;
+ bool needs_domain_update;
+ bool needs_server_update;
+};
+
+static gboolean compare_index(gconstpointer a, gconstpointer b)
+{
+ gint ai = GPOINTER_TO_UINT(a);
+ gint bi = GPOINTER_TO_UINT(b);
+
+ return ai == bi;
+}
+
+static void free_dns_interface(gpointer data)
+{
+ struct dns_interface *iface = data;
+
+ if (!iface)
+ return;
+
+ g_list_free_full(iface->domains, g_free);
+ g_list_free_full(iface->servers, g_free);
+
+ g_free(iface);
+}
+
+static void setlinkdns_append(DBusMessageIter *iter, void *user_data)
+{
+ struct dns_interface *iface = user_data;
+ int result;
+ unsigned int i;
+ int type;
+ char ipv4_bytes[4];
+ char ipv6_bytes[16];
+ GList *list;
+ DBusMessageIter address_array, struct_array, byte_array;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &iface->index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(iay)",
+ &address_array);
+
+ for (list = iface->servers; list; list = g_list_next(list)) {
+ char *server = list->data;
+
+ DBG("index: %d, server: %s", iface->index, server);
+
+ dbus_message_iter_open_container(&address_array,
+ DBUS_TYPE_STRUCT, NULL, &struct_array);
+
+ type = connman_inet_check_ipaddress(server);
+
+ if (type == AF_INET) {
+ result = inet_pton(type, server, ipv4_bytes);
+ if (!result) {
+ DBG("Failed to parse IPv4 address: %s",
+ server);
+ return;
+ }
+
+ dbus_message_iter_append_basic(&struct_array,
+ DBUS_TYPE_INT32, &type);
+
+ dbus_message_iter_open_container(&struct_array,
+ DBUS_TYPE_ARRAY, "y", &byte_array);
+
+ for (i = 0; i < sizeof(ipv4_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array,
+ DBUS_TYPE_BYTE,
+ &(ipv4_bytes[i]));
+ }
+
+ dbus_message_iter_close_container(&struct_array,
+ &byte_array);
+ } else if (type == AF_INET6) {
+ result = inet_pton(type, server, ipv6_bytes);
+ if (!result) {
+ DBG("Failed to parse IPv6 address: %s", server);
+ return;
+ }
+
+ dbus_message_iter_append_basic(&struct_array,
+ DBUS_TYPE_INT32, &type);
+
+ dbus_message_iter_open_container(&struct_array,
+ DBUS_TYPE_ARRAY, "y", &byte_array);
+
+ for (i = 0; i < sizeof(ipv6_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array,
+ DBUS_TYPE_BYTE,
+ &(ipv6_bytes[i]));
+ }
+
+ dbus_message_iter_close_container(&struct_array,
+ &byte_array);
+ }
+
+ dbus_message_iter_close_container(&address_array,
+ &struct_array);
+ }
+
+ dbus_message_iter_close_container(iter, &address_array);
+}
+
+static void setlinkdomains_append(DBusMessageIter *iter, void *user_data)
+{
+ struct dns_interface *iface = user_data;
+ GList *list;
+ DBusMessageIter domain_array, struct_array;
+ gboolean only_routing = FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &iface->index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(sb)",
+ &domain_array);
+
+ for (list = iface->domains; list; list = g_list_next(list)) {
+ char *domain = list->data;
+
+ DBG("index: %d, domain: %s", iface->index, domain);
+
+ dbus_message_iter_open_container(&domain_array,
+ DBUS_TYPE_STRUCT, NULL, &struct_array);
+
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_STRING,
+ &domain);
+
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_BOOLEAN,
+ &only_routing);
+
+ dbus_message_iter_close_container(&domain_array, &struct_array);
+ }
+
+ dbus_message_iter_close_container(iter, &domain_array);
+}
+
+static int set_systemd_resolved_values(struct dns_interface *iface)
+{
+ if (!resolved_proxy || !iface)
+ return -ENOENT;
+
+ /* No async error processing -- just fire and forget */
+
+ if (iface->needs_server_update) {
+ if (!g_dbus_proxy_method_call(resolved_proxy, "SetLinkDNS",
+ setlinkdns_append, NULL, iface, NULL))
+ return -EINVAL;
+
+ iface->needs_server_update = FALSE;
+ }
+
+ if (iface->needs_domain_update) {
+ if (!g_dbus_proxy_method_call(resolved_proxy, "SetLinkDomains",
+ setlinkdomains_append, NULL, iface, NULL))
+ return -EINVAL;
+
+ iface->needs_domain_update = FALSE;
+ }
+
+ return 0;
+}
+
+static bool is_empty(struct dns_interface *iface)
+{
+ if (!iface)
+ return FALSE;
+
+ return (!iface->domains && !iface->servers);
+}
+
+static void update_interface(gpointer key, gpointer value, gpointer data)
+{
+ struct dns_interface *iface = value;
+ GList **removed_items = data;
+
+ set_systemd_resolved_values(iface);
+
+ if (is_empty(iface))
+ *removed_items = g_list_prepend(*removed_items, iface);
+}
+
+static int update_systemd_resolved(gpointer data)
+{
+ GList *removed_items = NULL, *list;
+
+ if (!interface_hash) {
+ DBG("no interface hash when updating");
+
+ return G_SOURCE_REMOVE;
+ }
+
+ g_hash_table_foreach(interface_hash, update_interface, &removed_items);
+
+ for (list = removed_items; list; list = g_list_next(list)) {
+ struct dns_interface *iface = list->data;
+
+ g_hash_table_remove(interface_hash,
+ GUINT_TO_POINTER(iface->index));
+ }
+
+ g_list_free(removed_items);
+
+ update_interfaces_source = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static GList *remove_string(GList *str_list, const char *str)
+{
+ GList *match = NULL;
+
+ match = g_list_find_custom(str_list, str,
+ (GCompareFunc) g_strcmp0);
+ if (match) {
+ g_free(match->data);
+ return g_list_delete_link(str_list, match);
+ }
+
+ return str_list;
+}
+
+static void remove_values(struct dns_interface *iface, const char *domain,
+ const char *server)
+{
+ if (!iface)
+ return;
+
+ if (domain) {
+ iface->domains = remove_string(iface->domains, domain);
+ iface->needs_domain_update = TRUE;
+ }
+
+ if (server) {
+ iface->servers = remove_string(iface->servers, server);
+ iface->needs_server_update = TRUE;
+ }
+}
+
+int __connman_dnsproxy_remove(int index, const char *domain,
+ const char *server)
+{
+ struct dns_interface *iface;
+
+ DBG("%d, %s, %s", index, domain ? domain : "no domain",
+ server ? server : "no server");
+
+ if (!interface_hash || index < 0)
+ return -EINVAL;
+
+ iface = g_hash_table_lookup(interface_hash, GUINT_TO_POINTER(index));
+
+ if (!iface)
+ return -EINVAL;
+
+ remove_values(iface, domain, server);
+
+ if (!update_interfaces_source)
+ update_interfaces_source = g_idle_add(update_systemd_resolved,
+ NULL);
+
+ return 0;
+}
+
+static GList *replace_to_end(GList *str_list, const char *str)
+{
+ GList *list;
+
+ for (list = str_list; list; list = g_list_next(list)) {
+ char *orig = list->data;
+
+ if (g_strcmp0(orig, str) == 0) {
+ str_list = g_list_remove(str_list, orig);
+ g_free(orig);
+ break;
+ }
+ }
+
+ return g_list_append(str_list, g_strdup(str));
+}
+
+int __connman_dnsproxy_append(int index, const char *domain,
+ const char *server)
+{
+ struct dns_interface *iface;
+
+ DBG("%d, %s, %s", index, domain ? domain : "no domain",
+ server ? server : "no server");
+
+ if (!interface_hash || index < 0)
+ return -EINVAL;
+
+ iface = g_hash_table_lookup(interface_hash, GUINT_TO_POINTER(index));
+
+ if (!iface) {
+ iface = g_new0(struct dns_interface, 1);
+ if (!iface)
+ return -ENOMEM;
+
+ iface->index = index;
+ g_hash_table_replace(interface_hash, GUINT_TO_POINTER(index), iface);
+ }
+
+ if (domain) {
+ iface->domains = replace_to_end(iface->domains, domain);
+ iface->needs_domain_update = TRUE;
+ }
+
+ if (server) {
+ iface->servers = replace_to_end(iface->servers, server);
+ iface->needs_server_update = TRUE;
+ }
+
+ if (!update_interfaces_source)
+ update_interfaces_source = g_idle_add(update_systemd_resolved,
+ NULL);
+
+ return 0;
+}
+
+int __connman_dnsproxy_add_listener(int index)
+{
+ DBG("");
+
+ return -ENXIO;
+}
+
+void __connman_dnsproxy_remove_listener(int index)
+{
+ DBG("");
+}
+
+static int setup_resolved(void)
+{
+ connection = connman_dbus_get_connection();
+ if (!connection)
+ return -ENXIO;
+
+ client = g_dbus_client_new(connection, SYSTEMD_RESOLVED_SERVICE,
+ SYSTEMD_RESOLVED_PATH);
+
+ if (!client)
+ return -EINVAL;
+
+ resolved_proxy = g_dbus_proxy_new(client, SYSTEMD_RESOLVED_PATH,
+ "org.freedesktop.resolve1.Manager");
+
+ if (!resolved_proxy)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void setlinkmulticastdns_append(DBusMessageIter *iter, void *user_data) {
+ struct mdns_data *data = user_data;
+ char *val = "no";
+
+ if (data->enabled)
+ val = "yes";
+
+ DBG("SetLinkMulticastDNS: %d/%s", data->index, val);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &data->index);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &val);
+}
+
+int __connman_dnsproxy_set_mdns(int index, bool enabled)
+{
+ struct mdns_data data = { .index = index, .enabled = enabled };
+
+ if (!resolved_proxy)
+ return -ENOENT;
+
+ if (index < 0)
+ return -EINVAL;
+
+ if (!g_dbus_proxy_method_call(resolved_proxy, "SetLinkMulticastDNS",
+ setlinkmulticastdns_append, NULL, &data, NULL))
+ return -EINVAL;
+
+ return 0;
+}
+
+int __connman_dnsproxy_init(void)
+{
+ int ret;
+
+ DBG("");
+
+ ret = setup_resolved();
+ if (ret)
+ return ret;
+
+ interface_hash = g_hash_table_new_full(g_direct_hash,
+ compare_index,
+ NULL,
+ free_dns_interface);
+ if (!interface_hash)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void __connman_dnsproxy_cleanup(void)
+{
+ DBG("");
+
+ if (update_interfaces_source) {
+ /*
+ * It might be that we don't get to an idle loop anymore, so
+ * run the update function once more to clean up.
+ */
+ g_source_remove(update_interfaces_source);
+ update_systemd_resolved(NULL);
+ update_interfaces_source = 0;
+ }
+
+ if (interface_hash) {
+ g_hash_table_destroy(interface_hash);
+ interface_hash = NULL;
+ }
+
+ if (resolved_proxy) {
+ g_dbus_proxy_unref(resolved_proxy);
+ resolved_proxy = NULL;
+ }
+
+ if (client) {
+ g_dbus_client_unref(client);
+ client = NULL;
+ }
+
+ if (connection) {
+ dbus_connection_unref(connection);
+ connection = NULL;
+ }
+}
diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index 72c0d8f1..cb583251 100755
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -84,6 +84,11 @@ struct domain_hdr {
#error "Unknown byte order"
#endif
+struct qtype_qclass {
+ uint16_t qtype;
+ uint16_t qclass;
+} __attribute__ ((packed));
+
struct partial_reply {
uint16_t len;
uint16_t received;
@@ -489,7 +494,7 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
err, len, dns_len);
}
-static void send_response(int sk, unsigned char *buf, int len,
+static void send_response(int sk, unsigned char *buf, size_t len,
const struct sockaddr *to, socklen_t tolen,
int protocol)
{
@@ -501,21 +506,26 @@ static void send_response(int sk, unsigned char *buf, int len,
if (offset < 0)
return;
- if (len < 12)
+ if (len < sizeof(*hdr) + offset)
return;
hdr = (void *) (buf + offset);
+ if (offset) {
+ buf[0] = 0;
+ buf[1] = sizeof(*hdr);
+ }
debug("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
hdr->qr = 1;
hdr->rcode = ns_r_servfail;
+ hdr->qdcount = 0;
hdr->ancount = 0;
hdr->nscount = 0;
hdr->arcount = 0;
- err = sendto(sk, buf, len, MSG_NOSIGNAL, to, tolen);
+ err = sendto(sk, buf, sizeof(*hdr) + offset, MSG_NOSIGNAL, to, tolen);
if (err < 0) {
connman_error("Failed to send DNS response to %d: %s",
sk, strerror(errno));
@@ -2265,7 +2275,7 @@ static gboolean udp_server_event(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
unsigned char buf[4096];
- int sk, err, len;
+ int sk, len;
struct server_data *data = user_data;
if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -2277,12 +2287,9 @@ static gboolean udp_server_event(GIOChannel *channel, GIOCondition condition,
sk = g_io_channel_unix_get_fd(channel);
len = recv(sk, buf, sizeof(buf), 0);
- if (len < 12)
- return TRUE;
- err = forward_dns_reply(buf, len, IPPROTO_UDP, data);
- if (err < 0)
- return TRUE;
+ if (len >= 12)
+ forward_dns_reply(buf, len, IPPROTO_UDP, data);
#if defined TIZEN_EXT
GSList *list;
@@ -3137,34 +3144,41 @@ static void dnsproxy_default_changed(struct connman_service *service)
cache_refresh();
}
-static struct connman_notifier dnsproxy_notifier = {
+static const struct connman_notifier dnsproxy_notifier = {
.name = "dnsproxy",
.default_changed = dnsproxy_default_changed,
.offline_mode = dnsproxy_offline_mode,
};
-static unsigned char opt_edns0_type[2] = { 0x00, 0x29 };
+static const unsigned char opt_edns0_type[2] = { 0x00, 0x29 };
-static int parse_request(unsigned char *buf, int len,
+static int parse_request(unsigned char *buf, size_t len,
char *name, unsigned int size)
{
struct domain_hdr *hdr = (void *) buf;
uint16_t qdcount = ntohs(hdr->qdcount);
+ uint16_t ancount = ntohs(hdr->ancount);
+ uint16_t nscount = ntohs(hdr->nscount);
uint16_t arcount = ntohs(hdr->arcount);
unsigned char *ptr;
- char *last_label = NULL;
unsigned int remain, used = 0;
- if (len < 12)
+ if (len < sizeof(*hdr) + sizeof(struct qtype_qclass) ||
+ hdr->qr || qdcount != 1 || ancount || nscount) {
+ DBG("Dropped DNS request qr %d with len %zd qdcount %d "
+ "ancount %d nscount %d", hdr->qr, len, qdcount, ancount,
+ nscount);
+
+ return -EINVAL;
+ }
+
+ if (!name || !size)
return -EINVAL;
debug("id 0x%04x qr %d opcode %d qdcount %d arcount %d",
hdr->id, hdr->qr, hdr->opcode,
qdcount, arcount);
- if (hdr->qr != 0 || qdcount != 1)
- return -EINVAL;
-
name[0] = '\0';
ptr = buf + sizeof(struct domain_hdr);
@@ -3174,7 +3188,23 @@ static int parse_request(unsigned char *buf, int len,
uint8_t label_len = *ptr;
if (label_len == 0x00) {
- last_label = (char *) (ptr + 1);
+ uint8_t class;
+ struct qtype_qclass *q =
+ (struct qtype_qclass *)(ptr + 1);
+
+ if (remain < sizeof(*q)) {
+ DBG("Dropped malformed DNS query");
+ return -EINVAL;
+ }
+
+ class = ntohs(q->qclass);
+ if (class != 1 && class != 255) {
+ DBG("Dropped non-IN DNS class %d", class);
+ return -EINVAL;
+ }
+
+ ptr += sizeof(*q) + 1;
+ remain -= (sizeof(*q) + 1);
break;
}
@@ -3190,26 +3220,13 @@ static int parse_request(unsigned char *buf, int len,
remain -= label_len + 1;
}
- if (last_label && arcount && remain >= 9 && last_label[4] == 0 &&
- !memcmp(last_label + 5, opt_edns0_type, 2)) {
- uint16_t edns0_bufsize;
-
- edns0_bufsize = last_label[7] << 8 | last_label[8];
+ if (arcount && remain >= sizeof(struct domain_rr) + 1 && !ptr[0] &&
+ ptr[1] == opt_edns0_type[0] && ptr[2] == opt_edns0_type[1]) {
+ struct domain_rr *edns0 = (struct domain_rr *)(ptr + 1);
- debug("EDNS0 buffer size %u", edns0_bufsize);
-
- /* This is an evil hack until full TCP support has been
- * implemented.
- *
- * Somtimes the EDNS0 request gets send with a too-small
- * buffer size. Since glibc doesn't seem to crash when it
- * gets a response biffer then it requested, just bump
- * the buffer size up to 4KiB.
- */
- if (edns0_bufsize < 0x1000) {
- last_label[7] = 0x10;
- last_label[8] = 0x00;
- }
+ DBG("EDNS0 buffer size %u", ntohs(edns0->class));
+ } else if (!arcount && remain) {
+ DBG("DNS request with %d garbage bytes", remain);
}
debug("query %s", name);
@@ -3902,9 +3919,6 @@ static GIOChannel *get_listener(int family, int protocol, int index)
return NULL;
}
- /* ConnMan listens DNS from multiple interfaces
- * E.g. various technology based and tethering interfaces
- */
interface = connman_inet_ifname(index);
if (!interface || setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
interface,
@@ -3941,6 +3955,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
s.sin.sin_family = AF_INET;
s.sin.sin_port = htons(53);
slen = sizeof(s.sin);
+
if (__connman_inet_get_interface_address(index,
AF_INET,
&s.sin.sin_addr) < 0) {
@@ -3952,6 +3967,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
return NULL;
}
#endif
+
#if defined TIZEN_EXT
/* When ConnMan crashed,
* probably DNS listener cannot bind existing address */
@@ -3971,6 +3987,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
#endif
if (protocol == IPPROTO_TCP) {
+
#if !defined TIZEN_EXT
if (listen(sk, 10) < 0) {
connman_error("Failed to listen on TCP socket %d/%s",
@@ -3978,6 +3995,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
close(sk);
return NULL;
}
+
#endif
fcntl(sk, F_SETFL, O_NONBLOCK);
}
@@ -4275,6 +4293,11 @@ destroy:
return err;
}
+int __connman_dnsproxy_set_mdns(int index, bool enabled)
+{
+ return -ENOTSUP;
+}
+
void __connman_dnsproxy_cleanup(void)
{
DBG("");
@@ -4296,4 +4319,9 @@ void __connman_dnsproxy_cleanup(void)
g_hash_table_destroy(listener_table);
g_hash_table_destroy(partial_tcp_req_table);
+
+ if (ipv4_resolve)
+ g_resolv_unref(ipv4_resolve);
+ if (ipv6_resolve)
+ g_resolv_unref(ipv6_resolve);
}
diff --git a/src/firewall-iptables.c b/src/firewall-iptables.c
index 45943a82..1b04648b 100644
--- a/src/firewall-iptables.c
+++ b/src/firewall-iptables.c
@@ -92,15 +92,17 @@ static int insert_managed_chain(const char *table_name, int id)
managed_chain = g_strdup_printf("%s%s", CHAIN_PREFIX,
builtin_chains[id]);
- err = __connman_iptables_new_chain(table_name, managed_chain);
+ err = __connman_iptables_new_chain(AF_INET, table_name, managed_chain);
if (err < 0)
goto out;
rule = g_strdup_printf("-j %s", managed_chain);
- err = __connman_iptables_insert(table_name, builtin_chains[id], rule);
+ err = __connman_iptables_insert(AF_INET, table_name, builtin_chains[id],
+ rule);
g_free(rule);
if (err < 0) {
- __connman_iptables_delete_chain(table_name, managed_chain);
+ __connman_iptables_delete_chain(AF_INET, table_name,
+ managed_chain);
goto out;
}
@@ -119,13 +121,15 @@ static int delete_managed_chain(const char *table_name, int id)
builtin_chains[id]);
rule = g_strdup_printf("-j %s", managed_chain);
- err = __connman_iptables_delete(table_name, builtin_chains[id], rule);
+ err = __connman_iptables_delete(AF_INET, table_name, builtin_chains[id],
+ rule);
g_free(rule);
if (err < 0)
goto out;
- err = __connman_iptables_delete_chain(table_name, managed_chain);
+ err = __connman_iptables_delete_chain(AF_INET, table_name,
+ managed_chain);
out:
g_free(managed_chain);
@@ -178,7 +182,7 @@ static int insert_managed_rule(const char *table_name,
chain = g_strdup_printf("%s%s", CHAIN_PREFIX, chain_name);
out:
- err = __connman_iptables_append(table_name, chain, rule_spec);
+ err = __connman_iptables_append(AF_INET, table_name, chain, rule_spec);
g_free(chain);
@@ -197,14 +201,14 @@ static int delete_managed_rule(const char *table_name,
id = chain_to_index(chain_name);
if (id < 0) {
/* This chain is not managed */
- return __connman_iptables_delete(table_name, chain_name,
- rule_spec);
+ return __connman_iptables_delete(AF_INET, table_name,
+ chain_name, rule_spec);
}
managed_chain = g_strdup_printf("%s%s", CHAIN_PREFIX, chain_name);
- err = __connman_iptables_delete(table_name, managed_chain,
- rule_spec);
+ err = __connman_iptables_delete(AF_INET, table_name, managed_chain,
+ rule_spec);
for (list = managed_tables; list; list = list->next) {
mtable = list->data;
@@ -281,7 +285,7 @@ static int enable_rule(struct fw_rule *rule)
if (err < 0)
return err;
- err = __connman_iptables_commit(rule->table);
+ err = __connman_iptables_commit(AF_INET, rule->table);
if (err < 0)
return err;
@@ -304,7 +308,7 @@ static int disable_rule(struct fw_rule *rule)
return err;
}
- err = __connman_iptables_commit(rule->table);
+ err = __connman_iptables_commit(AF_INET, rule->table);
if (err < 0) {
connman_error("Cannot remove previously installed "
"iptables rules: %s", strerror(-err));
@@ -343,16 +347,8 @@ static void firewall_add_rule(struct firewall_context *ctx,
static void firewall_remove_rules(struct firewall_context *ctx)
{
- struct fw_rule *rule;
- GList *list;
-
- for (list = g_list_last(ctx->rules); list;
- list = g_list_previous(list)) {
- rule = list->data;
-
- ctx->rules = g_list_remove(ctx->rules, rule);
- cleanup_fw_rule(rule);
- }
+ g_list_free_full(ctx->rules, cleanup_fw_rule);
+ ctx->rules = NULL;
}
static int firewall_enable_rules(struct firewall_context *ctx)
@@ -399,14 +395,12 @@ 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",
+ "-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);
@@ -555,8 +549,8 @@ static void flush_table(const char *table_name)
char *rule, *managed_chain;
int id, err;
- __connman_iptables_iterate_chains(table_name, iterate_chains_cb,
- &chains);
+ __connman_iptables_iterate_chains(AF_INET, table_name,
+ iterate_chains_cb, &chains);
for (list = chains; list; list = list->next) {
id = GPOINTER_TO_INT(list->data);
@@ -565,7 +559,7 @@ static void flush_table(const char *table_name)
builtin_chains[id]);
rule = g_strdup_printf("-j %s", managed_chain);
- err = __connman_iptables_delete(table_name,
+ err = __connman_iptables_delete(AF_INET, table_name,
builtin_chains[id], rule);
if (err < 0) {
connman_warn("Failed to delete jump rule '%s': %s",
@@ -573,12 +567,14 @@ static void flush_table(const char *table_name)
}
g_free(rule);
- err = __connman_iptables_flush_chain(table_name, managed_chain);
+ err = __connman_iptables_flush_chain(AF_INET, table_name,
+ managed_chain);
if (err < 0) {
connman_warn("Failed to flush chain '%s': %s",
managed_chain, strerror(-err));
}
- err = __connman_iptables_delete_chain(table_name, managed_chain);
+ err = __connman_iptables_delete_chain(AF_INET, table_name,
+ managed_chain);
if (err < 0) {
connman_warn("Failed to delete chain '%s': %s",
managed_chain, strerror(-err));
@@ -587,7 +583,7 @@ static void flush_table(const char *table_name)
g_free(managed_chain);
}
- err = __connman_iptables_commit(table_name);
+ err = __connman_iptables_commit(AF_INET, table_name);
if (err < 0) {
connman_warn("Failed to flush table '%s': %s",
table_name, strerror(-err));
diff --git a/src/firewall-nftables.c b/src/firewall-nftables.c
index 1febce44..262b2a90 100644
--- a/src/firewall-nftables.c
+++ b/src/firewall-nftables.c
@@ -67,7 +67,7 @@
#define CONNMAN_CHAIN_NAT_POST "nat-postrouting"
#define CONNMAN_CHAIN_ROUTE_OUTPUT "route-output"
-static bool debug_enabled = true;
+static bool debug_enabled = false;
struct firewall_handle {
uint64_t handle;
@@ -402,6 +402,8 @@ static int table_cmd(struct mnl_socket *nl, struct nftnl_table *t,
uint32_t seq = 0;
int err;
+ bzero(buf, sizeof(buf));
+
batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
@@ -433,6 +435,8 @@ static int chain_cmd(struct mnl_socket *nl, struct nftnl_chain *chain,
uint32_t seq = 0;
int err;
+ bzero(buf, sizeof(buf));
+
batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
@@ -465,6 +469,8 @@ static int rule_cmd(struct mnl_socket *nl, struct nftnl_rule *rule,
uint32_t seq = 0;
int err;
+ bzero(buf, sizeof(buf));
+
debug_netlink_dump_rule(rule);
batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
@@ -670,7 +676,7 @@ static int build_rule_snat(int index, const char *address,
nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
- /* IOF */
+ /* OIF */
expr = nftnl_expr_alloc("meta");
if (!expr)
goto err;
@@ -1003,7 +1009,7 @@ static int create_table_and_chains(struct nftables_info *nft_info)
/*
* # nft add chain connman nat-prerouting \
- * { type nat hook prerouting priortiy 0 ; }
+ * { type nat hook prerouting priority 0 ; }
*/
chain = build_chain(CONNMAN_CHAIN_NAT_PRE, CONNMAN_TABLE,
"nat", NF_INET_PRE_ROUTING, 0);
@@ -1020,7 +1026,7 @@ static int create_table_and_chains(struct nftables_info *nft_info)
/*
* # nft add chain connman nat-postrouting \
- * { type nat hook postrouting priortiy 0 ; }
+ * { type nat hook postrouting priority 0 ; }
*/
chain = build_chain(CONNMAN_CHAIN_NAT_POST, CONNMAN_TABLE,
"nat", NF_INET_POST_ROUTING, 0);
diff --git a/src/inet.c b/src/inet.c
index d54760d3..08b1a25f 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -25,7 +25,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
@@ -262,6 +261,40 @@ char *connman_inet_ifname2addr(const char *name)
}
#endif
+bool __connman_inet_is_any_addr(const char *address, int family)
+{
+ bool ret = false;
+ struct addrinfo hints;
+ struct addrinfo *result = NULL;
+ struct sockaddr_in6 *in6 = NULL;
+ struct sockaddr_in *in4 = NULL;
+
+ if (!address || !*address)
+ goto out;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+
+ hints.ai_family = family;
+
+ if (getaddrinfo(address, NULL, &hints, &result))
+ goto out;
+
+ if (result) {
+ if (result->ai_family == AF_INET6) {
+ in6 = (struct sockaddr_in6*)result->ai_addr;
+ ret = IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr);
+ } else if (result->ai_family == AF_INET) {
+ in4 = (struct sockaddr_in*)result->ai_addr;
+ ret = in4->sin_addr.s_addr == INADDR_ANY;
+ }
+
+ freeaddrinfo(result);
+ }
+
+out:
+ return ret;
+}
+
int connman_inet_ifindex(const char *name)
{
struct ifreq ifr;
@@ -442,6 +475,40 @@ void connman_inet_update_device_ident(struct connman_device *device)
}
#endif
+bool connman_inet_is_ifup(int index)
+{
+ int sk;
+ struct ifreq ifr;
+ bool ret = false;
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0) {
+ connman_warn("Failed to open socket");
+ return false;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ connman_warn("Failed to get interface name for interface %d", index);
+ goto done;
+ }
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+ connman_warn("Failed to get interface flags for index %d", index);
+ goto done;
+ }
+
+ if (ifr.ifr_flags & IFF_UP)
+ ret = true;
+
+done:
+ close(sk);
+
+ return ret;
+}
+
struct in6_ifreq {
struct in6_addr ifr6_addr;
__u32 ifr6_prefixlen;
@@ -590,7 +657,17 @@ int connman_inet_add_network_route(int index, const char *host,
memset(&rt, 0, sizeof(rt));
rt.rt_flags = RTF_UP;
- if (gateway)
+
+ /*
+ * Set RTF_GATEWAY only when gateway is set and the gateway IP address
+ * is not IPv4 any address (0.0.0.0). If the given gateway IP address is
+ * any address adding of route will fail when RTF_GATEWAY set. Passing
+ * gateway as NULL or INADDR_ANY should have the same effect. Setting
+ * the gateway address later to the struct is not affected by this,
+ * since given IPv4 any address (0.0.0.0) equals the value set with
+ * INADDR_ANY.
+ */
+ if (gateway && !__connman_inet_is_any_addr(gateway, AF_INET))
rt.rt_flags |= RTF_GATEWAY;
if (!netmask)
rt.rt_flags |= RTF_HOST;
@@ -753,10 +830,17 @@ int connman_inet_add_ipv6_network_route(int index, const char *host,
rt.rtmsg_flags = RTF_UP | RTF_HOST;
- if (gateway) {
+ /*
+ * Set RTF_GATEWAY only when gateway is set, the gateway IP address is
+ * not IPv6 any address (e.g., ::) and the address is valid (conversion
+ * succeeds). If the given gateway IP address is any address then
+ * adding of route will fail when RTF_GATEWAY set. Passing gateway as
+ * NULL or IPv6 any address should have the same effect.
+ */
+
+ if (gateway && !__connman_inet_is_any_addr(gateway, AF_INET6) &&
+ inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) > 0)
rt.rtmsg_flags |= RTF_GATEWAY;
- inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
- }
rt.rtmsg_metric = 1;
rt.rtmsg_ifindex = index;
@@ -2433,6 +2517,7 @@ static gboolean inet_rtnl_event(GIOChannel *chan, GIOCondition cond,
return TRUE;
cleanup:
+ rtnl_data->callback(NULL, rtnl_data->user_data);
inet_rtnl_cleanup(rtnl_data);
return TRUE;
}
@@ -2585,8 +2670,6 @@ out:
data->callback(addr, index, data->user_data);
g_free(data);
-
- return;
}
/*
@@ -2678,9 +2761,10 @@ int connman_inet_check_ipaddress(const char *host)
addr = NULL;
result = getaddrinfo(host, NULL, &hints, &addr);
- if (result == 0)
+ if (result == 0) {
result = addr->ai_family;
- freeaddrinfo(addr);
+ freeaddrinfo(addr);
+ }
return result;
}
@@ -2799,8 +2883,7 @@ char **__connman_inet_get_running_interfaces(void)
g_free(ifr);
- if (count < numif)
- {
+ if (count < numif) {
char **prev_result = result;
result = g_try_realloc(result, (count + 1) * sizeof(char *));
if (!result) {
@@ -2883,6 +2966,41 @@ out:
return err;
}
+int __connman_inet_get_interface_mac_address(int index, uint8_t *mac_address)
+{
+ struct ifreq ifr;
+ int sk, err;
+ int ret = -EINVAL;
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0) {
+ DBG("Open socket error");
+ return ret;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = index;
+
+ err = ioctl(sk, SIOCGIFNAME, &ifr);
+ if (err < 0) {
+ DBG("Get interface name error");
+ goto done;
+ }
+
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+ if (err < 0) {
+ DBG("Get MAC address error");
+ goto done;
+ }
+
+ memcpy(mac_address, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+ ret = 0;
+
+done:
+ close(sk);
+ return ret;
+}
+
static int iprule_modify(int cmd, int family, uint32_t table_id,
uint32_t fwmark)
{
@@ -2945,12 +3063,15 @@ int __connman_inet_del_fwmark_rule(uint32_t table_id, int family, uint32_t fwmar
}
static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
- const char *gateway)
+ const char *gateway, unsigned char prefixlen)
{
struct __connman_inet_rtnl_handle rth;
unsigned char buf[sizeof(struct in6_addr)];
int ret, len;
int family = connman_inet_check_ipaddress(gateway);
+ char *dst = NULL;
+
+ DBG("gateway %s/%u table %u", gateway, prefixlen, table_id);
switch (family) {
case AF_INET:
@@ -2963,7 +3084,19 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
return -EINVAL;
}
- ret = inet_pton(family, gateway, buf);
+ if (prefixlen) {
+ struct in_addr ipv4_subnet_addr, ipv4_mask;
+
+ memset(&ipv4_subnet_addr, 0, sizeof(ipv4_subnet_addr));
+ ipv4_mask.s_addr = htonl((0xffffffff << (32 - prefixlen)) & 0xffffffff);
+ ipv4_subnet_addr.s_addr = inet_addr(gateway);
+ ipv4_subnet_addr.s_addr &= ipv4_mask.s_addr;
+
+ dst = g_strdup(inet_ntoa(ipv4_subnet_addr));
+ }
+
+ ret = inet_pton(family, dst ? dst : gateway, buf);
+ g_free(dst);
if (ret <= 0)
return -EINVAL;
@@ -2978,9 +3111,11 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
rth.req.u.r.rt.rtm_protocol = RTPROT_BOOT;
rth.req.u.r.rt.rtm_scope = RT_SCOPE_UNIVERSE;
rth.req.u.r.rt.rtm_type = RTN_UNICAST;
+ rth.req.u.r.rt.rtm_dst_len = prefixlen;
+
+ __connman_inet_rtnl_addattr_l(&rth.req.n, sizeof(rth.req),
+ prefixlen > 0 ? RTA_DST : RTA_GATEWAY, buf, len);
- __connman_inet_rtnl_addattr_l(&rth.req.n, sizeof(rth.req), RTA_GATEWAY,
- buf, len);
if (table_id < 256) {
rth.req.u.r.rt.rtm_table = table_id;
} else {
@@ -3009,7 +3144,14 @@ int __connman_inet_add_default_to_table(uint32_t table_id, int ifindex,
{
/* ip route add default via 1.2.3.4 dev wlan0 table 1234 */
- return iproute_default_modify(RTM_NEWROUTE, table_id, ifindex, gateway);
+ return iproute_default_modify(RTM_NEWROUTE, table_id, ifindex, gateway, 0);
+}
+
+int __connman_inet_add_subnet_to_table(uint32_t table_id, int ifindex,
+ const char *gateway, unsigned char prefixlen)
+{
+ /* ip route add 1.2.3.4/24 dev eth0 table 1234 */
+ return iproute_default_modify(RTM_NEWROUTE, table_id, ifindex, gateway, prefixlen);
}
int __connman_inet_del_default_from_table(uint32_t table_id, int ifindex,
@@ -3017,7 +3159,14 @@ int __connman_inet_del_default_from_table(uint32_t table_id, int ifindex,
{
/* ip route del default via 1.2.3.4 dev wlan0 table 1234 */
- return iproute_default_modify(RTM_DELROUTE, table_id, ifindex, gateway);
+ return iproute_default_modify(RTM_DELROUTE, table_id, ifindex, gateway, 0);
+}
+
+int __connman_inet_del_subnet_from_table(uint32_t table_id, int ifindex,
+ const char *gateway, unsigned char prefixlen)
+{
+ /* ip route del 1.2.3.4/24 dev eth0 table 1234 */
+ return iproute_default_modify(RTM_DELROUTE, table_id, ifindex, gateway, prefixlen);
}
int __connman_inet_get_interface_ll_address(int index, int family,
@@ -3152,10 +3301,8 @@ static int get_nfs_server_ip(const char *cmdline_file, const char *pnp_file,
pnp_file, error->message);
goto out;
}
- } else {
- connman_error("%s: File %s doesn't exist\n", __func__, pnp_file);
+ } else
goto out;
- }
len = strlen(cmdline);
if (len <= 1) {
@@ -3351,6 +3498,9 @@ char **__connman_inet_get_pnp_nameservers(const char *pnp_file)
if (!pnp_file)
pnp_file = "/proc/net/pnp";
+ if (!g_file_test(pnp_file, G_FILE_TEST_EXISTS))
+ goto out;
+
if (!g_file_get_contents(pnp_file, &pnp, NULL, &error)) {
connman_error("%s: Cannot read %s %s\n", __func__,
pnp_file, error->message);
diff --git a/src/ipconfig.c b/src/ipconfig.c
index d94b8734..fb39f64d 100755
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -1157,6 +1157,7 @@ static struct connman_ipconfig *create_ipv6config(int index)
#else
ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy = 2;
#endif
+
ipv6config->address = connman_ipaddress_alloc(AF_INET6);
if (!ipv6config->address) {
g_free(ipv6config);
@@ -2104,6 +2105,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
disable_ipv6(ipconfig);
#endif
+
break;
case CONNMAN_IPCONFIG_METHOD_AUTO:
@@ -2116,6 +2118,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
#if defined TIZEN_EXT
enable_ipv6(ipconfig);
#endif
+
break;
case CONNMAN_IPCONFIG_METHOD_MANUAL:
diff --git a/src/ippool.c b/src/ippool.c
index cea1dccd..f2e9b000 100755
--- a/src/ippool.c
+++ b/src/ippool.c
@@ -28,7 +28,6 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include <sys/errno.h>
#include <sys/socket.h>
#include "connman.h"
@@ -43,8 +42,6 @@ struct address_info {
};
struct connman_ippool {
- unsigned int refcount;
-
struct address_info *info;
char *gateway;
@@ -65,30 +62,11 @@ static uint32_t block_20_bits;
static uint32_t block_24_bits;
static uint32_t subnet_mask_24;
-struct connman_ippool *
-__connman_ippool_ref_debug(struct connman_ippool *pool,
- const char *file, int line, const char *caller)
-{
- DBG("%p ref %d by %s:%d:%s()", pool, pool->refcount + 1,
- file, line, caller);
-
- __sync_fetch_and_add(&pool->refcount, 1);
-
- return pool;
-}
-
-void __connman_ippool_unref_debug(struct connman_ippool *pool,
- const char *file, int line, const char *caller)
+void __connman_ippool_free(struct connman_ippool *pool)
{
if (!pool)
return;
- DBG("%p ref %d by %s:%d:%s()", pool, pool->refcount - 1,
- file, line, caller);
-
- if (__sync_fetch_and_sub(&pool->refcount, 1) != 1)
- return;
-
if (pool->info) {
allocated_blocks = g_slist_remove(allocated_blocks, pool->info);
g_free(pool->info);
@@ -386,7 +364,6 @@ struct connman_ippool *__connman_ippool_create(int index,
info->start = block;
info->end = block + range;
- pool->refcount = 1;
pool->info = info;
pool->collision_cb = collision_cb;
pool->user_data = user_data;
diff --git a/src/iptables.c b/src/iptables.c
index aaddf9d6..9cfd80f8 100755
--- a/src/iptables.c
+++ b/src/iptables.c
@@ -28,12 +28,14 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include <sys/errno.h>
+#include <errno.h>
#include <sys/socket.h>
#include <xtables.h>
#include <inttypes.h>
+#include <setjmp.h>
#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
#include "connman.h"
#include "src/shared/util.h"
@@ -128,6 +130,10 @@
* End of CHAIN
*/
+/*
+ * Values for the index values used here are defined as equal for both IPv4
+ * and IPv6 (NF_IP_* and NF_IP6_*) in Netfilter headers.
+ */
static const char *hooknames[] = {
[NF_IP_PRE_ROUTING] = "PREROUTING",
[NF_IP_LOCAL_IN] = "INPUT",
@@ -143,29 +149,25 @@ static const char *hooknames[] = {
#define XT_OPTION_OFFSET_SCALE 256
-#define MIN_ALIGN (__alignof__(struct ipt_entry))
-
-#define ALIGN(s) (((s) + ((MIN_ALIGN)-1)) & ~((MIN_ALIGN)-1))
-
-struct error_target {
- struct xt_entry_target t;
- char error[IPT_TABLE_MAXNAMELEN];
-};
-
struct connman_iptables_entry {
- int offset;
+ int type;
+ unsigned int offset;
int builtin;
int counter_idx;
struct ipt_entry *entry;
+ struct ip6t_entry *entry6;
};
struct connman_iptables {
+ int type;
char *name;
int ipt_sock;
struct ipt_getinfo *info;
struct ipt_get_entries *blob_entries;
+ struct ip6t_getinfo *info6;
+ struct ip6t_get_entries *blob_entries6;
unsigned int num_entries;
unsigned int old_entries;
@@ -178,11 +180,307 @@ struct connman_iptables {
};
static GHashTable *table_hash = NULL;
+static GHashTable *table_hash_ipv6 = NULL;
static bool debug_enabled = false;
-typedef int (*iterate_entries_cb_t)(struct ipt_entry *entry, int builtin,
- unsigned int hook, size_t size,
- unsigned int offset, void *user_data);
+struct iptables_ip {
+ int type;
+ struct ipt_ip *ip;
+ struct ip6t_ip6 *ip6;
+};
+
+struct iptables_replace {
+ int type;
+ struct ipt_replace *r;
+ struct ip6t_replace *r6;
+};
+
+static jmp_buf env_state;
+static bool jmp_set = false;
+
+static void enable_jmp()
+{
+ jmp_set = true;
+}
+
+static void disable_jmp()
+{
+ jmp_set = false;
+}
+
+static bool can_jmp()
+{
+ DBG("%s", jmp_set ? "true" : "false");
+ return jmp_set;
+}
+
+typedef int (*iterate_entries_cb_t)(struct connman_iptables_entry *entry,
+ int builtin, unsigned int hook,
+ size_t size, unsigned int offset,
+ void *user_data);
+
+static u_int16_t iptables_entry_get_next_offset(
+ struct connman_iptables_entry *entry)
+{
+ if (!entry)
+ return 0;
+
+ switch (entry->type) {
+ case AF_INET:
+ return entry->entry ? entry->entry->next_offset : 0;
+ case AF_INET6:
+ return entry->entry6 ? entry->entry6->next_offset : 0;
+ }
+
+ return 0;
+}
+
+static u_int16_t iptables_entry_get_target_offset(
+ struct connman_iptables_entry *entry)
+{
+ if (!entry)
+ return 0;
+
+ switch (entry->type) {
+ case AF_INET:
+ return entry->entry ? entry->entry->target_offset : 0;
+ case AF_INET6:
+ return entry->entry6 ? entry->entry6->target_offset : 0;
+ }
+
+ return 0;
+}
+
+static unsigned char *iptables_entry_get_elems(
+ struct connman_iptables_entry *entry)
+{
+ if (!entry)
+ return NULL;
+
+ switch (entry->type) {
+ case AF_INET:
+ return entry->entry ? entry->entry->elems : NULL;
+ case AF_INET6:
+ return entry->entry6 ? entry->entry6->elems : NULL;
+ }
+
+ return NULL;
+}
+
+static struct xt_entry_target *iptables_entry_get_target(
+ struct connman_iptables_entry *entry)
+{
+ if (!entry)
+ return NULL;
+
+ switch (entry->type) {
+ case AF_INET:
+ return entry->entry ? ipt_get_target(entry->entry) : NULL;
+ case AF_INET6:
+ return entry->entry6 ? ip6t_get_target(entry->entry6) : NULL;
+ }
+
+ return NULL;
+}
+
+static struct xt_counters *iptables_entry_get_counters(
+ struct connman_iptables_entry *entry)
+{
+ if (!entry)
+ return NULL;
+
+ switch (entry->type) {
+ case AF_INET:
+ return entry->entry ? &entry->entry->counters : NULL;
+ case AF_INET6:
+ return entry->entry6 ? &entry->entry6->counters : NULL;
+ }
+
+ return NULL;
+}
+
+static void iptables_entry_free(struct connman_iptables_entry *entry)
+{
+ if (!entry)
+ return;
+
+ g_free(entry->entry);
+ g_free(entry->entry6);
+ g_free(entry);
+}
+
+static const char *iptables_table_get_info_name(struct connman_iptables* table)
+{
+ if (!table)
+ return NULL;
+
+ switch (table->type) {
+ case AF_INET:
+ return table->info->name;
+ case AF_INET6:
+ return table->info6->name;
+ }
+
+ return NULL;
+}
+
+static unsigned int iptables_table_get_info_num_entries(
+ struct connman_iptables* table)
+{
+ if (!table)
+ return 0;
+
+ switch (table->type) {
+ case AF_INET:
+ return table->info->num_entries;
+ case AF_INET6:
+ return table->info6->num_entries;
+ }
+
+ return 0;
+}
+
+static unsigned int iptables_table_get_info_size(struct connman_iptables* table)
+{
+ if (!table)
+ return 0;
+
+ switch (table->type) {
+ case AF_INET:
+ return table->info->size;
+ case AF_INET6:
+ return table->info6->size;
+ }
+
+ return 0;
+}
+
+static unsigned int iptables_table_get_info_valid_hooks(
+ struct connman_iptables* table)
+{
+ if (!table)
+ return 0;
+
+ switch (table->type) {
+ case AF_INET:
+ return table->info->valid_hooks;
+ case AF_INET6:
+ return table->info6->valid_hooks;
+ }
+
+ return 0;
+}
+
+static unsigned int *iptables_table_get_info_hook_entry(
+ struct connman_iptables* table)
+{
+ if (!table)
+ return NULL;
+
+ switch (table->type) {
+ case AF_INET:
+ return table->info->hook_entry;
+ case AF_INET6:
+ return table->info6->hook_entry;
+ }
+
+ return NULL;
+}
+
+static unsigned int *iptables_table_get_info_underflow(
+ struct connman_iptables* table)
+{
+ if (!table)
+ return NULL;
+
+ switch (table->type) {
+ case AF_INET:
+ return table->info->underflow;
+ case AF_INET6:
+ return table->info6->underflow;
+ }
+
+ return NULL;
+}
+
+static unsigned int iptables_table_get_entries_size(
+ struct connman_iptables* table)
+{
+ if (!table)
+ return 0;
+
+ switch (table->type) {
+ case AF_INET:
+ return table->blob_entries->size;
+ case AF_INET6:
+ return table->blob_entries6->size;
+ }
+
+ return 0;
+}
+
+static const char *get_error_target(int type)
+{
+ switch (type) {
+ case AF_INET:
+ return IPT_ERROR_TARGET;
+ case AF_INET6:
+ return IP6T_ERROR_TARGET;
+ default:
+ return XT_ERROR_TARGET;
+ }
+}
+
+static const char *get_standard_target(int type)
+{
+ switch (type) {
+ case AF_INET:
+ return IPT_STANDARD_TARGET;
+ case AF_INET6:
+ return IP6T_STANDARD_TARGET;
+ default:
+ return XT_STANDARD_TARGET;
+ }
+}
+
+static struct connman_iptables *hash_table_lookup(int type,
+ const char *table_name) {
+
+ switch (type) {
+ case AF_INET:
+ return g_hash_table_lookup(table_hash, table_name);
+ case AF_INET6:
+ return g_hash_table_lookup(table_hash_ipv6, table_name);
+ }
+
+ return NULL;
+}
+
+static bool hash_table_replace(int type,
+ char *table_name,
+ struct connman_iptables *table) {
+
+ switch (type) {
+ case AF_INET:
+ return g_hash_table_replace(table_hash, table_name, table);
+ case AF_INET6:
+ return g_hash_table_replace(table_hash_ipv6, table_name, table);
+ }
+
+ return false;
+}
+
+static bool hash_table_remove(int type, const char *table_name)
+{
+ switch (type) {
+ case AF_INET:
+ return g_hash_table_remove(table_hash, table_name);
+ case AF_INET6:
+ return g_hash_table_remove(table_hash_ipv6, table_name);
+ }
+
+ return false;
+}
static unsigned int next_hook_entry_index(unsigned int *valid_hooks)
{
@@ -197,7 +495,7 @@ static unsigned int next_hook_entry_index(unsigned int *valid_hooks)
return h;
}
-static int iterate_entries(struct ipt_entry *entries,
+static int iterate_entries(struct connman_iptables_entry *entries,
unsigned int valid_hooks,
unsigned int *hook_entry,
unsigned int *underflow,
@@ -206,15 +504,45 @@ static int iterate_entries(struct ipt_entry *entries,
{
unsigned int offset, h, hook;
int builtin, err;
- struct ipt_entry *entry;
+ struct connman_iptables_entry entry;
+
+ if (!entries)
+ return -EINVAL;
+
+ switch (entries->type) {
+ case AF_INET:
+ if (!entries->entry)
+ return -EINVAL;
+
+ break;
+ case AF_INET6:
+ if (!entries->entry6)
+ return -EINVAL;
+
+ break;
+ default:
+ return -EINVAL;
+ }
h = next_hook_entry_index(&valid_hooks);
hook = h;
- for (offset = 0, entry = entries; offset < size;
- offset += entry->next_offset) {
+ entry.type = entries->type;
+ entry.entry = entries->entry;
+ entry.entry6 = entries->entry6;
+
+ for (offset = 0; offset < size;
+ offset += iptables_entry_get_next_offset(&entry)) {
builtin = -1;
- entry = (void *)entries + offset;
+
+ switch (entries->type) {
+ case AF_INET:
+ entry.entry = (void* )entries->entry + offset;
+ break;
+ case AF_INET6:
+ entry.entry6 = (void* )entries->entry6 + offset;
+ break;
+ }
/*
* Updating builtin, hook and h is very tricky.
@@ -239,7 +567,7 @@ static int iterate_entries(struct ipt_entry *entries,
if (h < NF_INET_NUMHOOKS && underflow[h] <= offset)
h = next_hook_entry_index(&valid_hooks);
- err = cb(entry, builtin, hook, size, offset, user_data);
+ err = cb(&entry, builtin, hook, size, offset, user_data);
if (err < 0)
return err;
}
@@ -247,15 +575,20 @@ static int iterate_entries(struct ipt_entry *entries,
return 0;
}
-static int print_entry(struct ipt_entry *entry, int builtin, unsigned int hook,
- size_t size, unsigned int offset,
- void *user_data)
+static int print_entry(struct connman_iptables_entry *entry, int builtin,
+ unsigned int hook, size_t size,
+ unsigned int offset, void *user_data)
{
- iterate_entries_cb_t cb = user_data;
+ iterate_entries_cb_t cb;
+ struct xt_counters *counters;
- 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);
+ cb = user_data;
+ counters = iptables_entry_get_counters(entry);
+
+ DBG("entry %p hook %u offset %u size %u packets %"PRIu64" "
+ "bytes %"PRIu64, entry, hook, offset,
+ iptables_entry_get_next_offset(entry),
+ (uint64_t) counters->pcnt, (uint64_t) counters->bcnt);
return cb(entry, builtin, hook, size, offset, NULL);
}
@@ -292,9 +625,12 @@ static bool is_jump(struct connman_iptables_entry *e)
{
struct xt_entry_target *target;
- target = ipt_get_target(e->entry);
+ target = iptables_entry_get_target(e);
+
+ if (!target)
+ return false;
- if (!g_strcmp0(target->u.user.name, IPT_STANDARD_TARGET)) {
+ if (!g_strcmp0(target->u.user.name, get_standard_target(e->type))) {
struct xt_standard_target *t;
t = (struct xt_standard_target *)target;
@@ -319,8 +655,12 @@ static bool is_fallthrough(struct connman_iptables_entry *e)
{
struct xt_entry_target *target;
- target = ipt_get_target(e->entry);
- if (!g_strcmp0(target->u.user.name, IPT_STANDARD_TARGET)) {
+ target = iptables_entry_get_target(e);
+
+ if (!target)
+ return false;
+
+ if (!g_strcmp0(target->u.user.name, get_standard_target(e->type))) {
struct xt_standard_target *t;
t = (struct xt_standard_target *)target;
@@ -333,15 +673,20 @@ static bool is_fallthrough(struct connman_iptables_entry *e)
static bool is_chain(struct connman_iptables *table,
struct connman_iptables_entry *e)
{
- struct ipt_entry *entry;
struct xt_entry_target *target;
- entry = e->entry;
+ if (!e)
+ return false;
+
if (e->builtin >= 0)
return true;
- target = ipt_get_target(entry);
- if (!g_strcmp0(target->u.user.name, IPT_ERROR_TARGET))
+ target = iptables_entry_get_target(e);
+
+ if (!target)
+ return false;
+
+ if (!g_strcmp0(target->u.user.name, get_error_target(e->type)))
return true;
return false;
@@ -352,23 +697,35 @@ static GList *find_chain_head(struct connman_iptables *table,
{
GList *list;
struct connman_iptables_entry *head;
- struct ipt_entry *entry;
struct xt_entry_target *target;
int builtin;
+
+ switch (table->type) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ return NULL;
+ }
for (list = table->entries; list; list = list->next) {
head = list->data;
- entry = head->entry;
/* Buit-in chain */
builtin = head->builtin;
+
if (builtin >= 0 && !g_strcmp0(hooknames[builtin], chain_name))
break;
/* User defined chain */
- target = ipt_get_target(entry);
- if (!g_strcmp0(target->u.user.name, IPT_ERROR_TARGET) &&
- !g_strcmp0((char *)target->data, chain_name))
+ target = iptables_entry_get_target(head);
+
+ if (!target)
+ continue;
+
+ if (!g_strcmp0(target->u.user.name,
+ get_error_target(table->type)) &&
+ !g_strcmp0((char *)target->data, chain_name))
break;
}
@@ -397,7 +754,6 @@ static GList *find_chain_tail(struct connman_iptables *table,
return g_list_last(table->entries);
}
-
static void update_offsets(struct connman_iptables *table)
{
GList *list, *prev;
@@ -416,7 +772,8 @@ static void update_offsets(struct connman_iptables *table)
prev_entry = prev->data;
entry->offset = prev_entry->offset +
- prev_entry->entry->next_offset;
+ iptables_entry_get_next_offset(
+ prev_entry);
}
}
@@ -428,9 +785,9 @@ static void update_targets_reference(struct connman_iptables *table,
struct connman_iptables_entry *tmp;
struct xt_standard_target *t;
GList *list;
- int offset;
+ unsigned int offset;
- offset = modified_entry->entry->next_offset;
+ offset = iptables_entry_get_next_offset(modified_entry);
for (list = table->entries; list; list = list->next) {
tmp = list->data;
@@ -438,7 +795,11 @@ static void update_targets_reference(struct connman_iptables *table,
if (!is_jump(tmp))
continue;
- t = (struct xt_standard_target *)ipt_get_target(tmp->entry);
+ t = (struct xt_standard_target *)
+ iptables_entry_get_target(tmp);
+
+ if (!t)
+ continue;
if (is_removing) {
if (t->verdict >= entry_before->offset)
@@ -451,40 +812,56 @@ static void update_targets_reference(struct connman_iptables *table,
if (is_fallthrough(modified_entry)) {
t = (struct xt_standard_target *)
- ipt_get_target(modified_entry->entry);
+ iptables_entry_get_target(modified_entry);
+
+ if (!t)
+ return;
t->verdict = entry_before->offset +
- modified_entry->entry->target_offset +
- ALIGN(sizeof(struct xt_standard_target));
+ iptables_entry_get_target_offset(modified_entry) +
+ XT_ALIGN(sizeof(struct xt_standard_target));
t->target.u.target_size =
- ALIGN(sizeof(struct xt_standard_target));
+ XT_ALIGN(sizeof(struct xt_standard_target));
}
}
static int iptables_add_entry(struct connman_iptables *table,
- struct ipt_entry *entry, GList *before,
- int builtin, int counter_idx)
+ struct connman_iptables_entry *entry,
+ GList *before, int builtin, int counter_idx)
{
struct connman_iptables_entry *e, *entry_before;
- if (!table)
- return -1;
+ if (!table) {
+ return -EINVAL;
+ }
e = g_try_malloc0(sizeof(struct connman_iptables_entry));
if (!e)
- return -1;
+ return -ENOMEM;
+
+ switch (table->type) {
+ case AF_INET:
+ e->entry = entry->entry;
+ break;
+ case AF_INET6:
+ e->entry6 = entry->entry6;
+ break;
+ default:
+ g_free(e);
+ return -EINVAL;
+ }
- e->entry = entry;
+ e->type = entry->type;
e->builtin = builtin;
e->counter_idx = counter_idx;
table->entries = g_list_insert_before(table->entries, before, e);
table->num_entries++;
- table->size += entry->next_offset;
+ table->size += iptables_entry_get_next_offset(e);
if (!before) {
- e->offset = table->size - entry->next_offset;
-
+ e->offset = table->size -
+ iptables_entry_get_next_offset(e);
return 0;
}
@@ -505,15 +882,17 @@ static int remove_table_entry(struct connman_iptables *table,
struct connman_iptables_entry *entry)
{
int removed = 0;
+ u_int16_t next_offset;
+ next_offset = iptables_entry_get_next_offset(entry);
table->num_entries--;
- table->size -= entry->entry->next_offset;
- removed = entry->entry->next_offset;
+
+ table->size -= next_offset;
+ removed = next_offset;
table->entries = g_list_remove(table->entries, entry);
- g_free(entry->entry);
- g_free(entry);
+ iptables_entry_free(entry);
return removed;
}
@@ -590,16 +969,30 @@ static int iptables_add_chain(struct connman_iptables *table,
const char *name)
{
GList *last;
- struct ipt_entry *entry_head;
- struct ipt_entry *entry_return;
- struct error_target *error;
- struct ipt_standard_target *standard;
+ struct ipt_entry *entry_head = NULL;
+ struct ipt_entry *entry_return = NULL;
+ struct ip6t_entry *entry6_head = NULL;
+ struct ip6t_entry *entry6_return = NULL;
+ struct connman_iptables_entry entry = { 0 };
+ struct xt_error_target *error = NULL;
+ struct ipt_standard_target *standard = NULL;
u_int16_t entry_head_size, entry_return_size;
+ size_t entry_struct_size = 0;
+ size_t xt_error_target_size = 0;
+ size_t standard_target_size = 0;
DBG("table %s chain %s", table->name, name);
+ entry.type = table->type;
+
+ /* Do not allow to add duplicate chains */
+ if (find_chain_head(table, name))
+ return -EEXIST;
+
last = g_list_last(table->entries);
+ xt_error_target_size = XT_ALIGN(sizeof(struct xt_error_target));
+
/*
* An empty chain is composed of:
* - A head entry, with no match and an error target.
@@ -610,47 +1003,93 @@ static int iptables_add_chain(struct connman_iptables *table,
*/
/* head entry */
- entry_head_size = ALIGN(sizeof(struct ipt_entry)) +
- ALIGN(sizeof(struct error_target));
- entry_head = g_try_malloc0(entry_head_size);
- if (!entry_head)
- goto err_head;
+ switch (entry.type) {
+ case AF_INET:
+ entry_struct_size = XT_ALIGN(sizeof(struct ipt_entry));
+ entry_head_size = entry_struct_size + xt_error_target_size;
+
+ entry_head = g_try_malloc0(entry_head_size);
+ if (!entry_head)
+ goto err_head;
+
+ entry_head->target_offset = entry_struct_size;
+ entry_head->next_offset = entry_head_size;
+
+ error = (struct xt_error_target *) entry_head->elems;
+
+ entry.entry = entry_head;
+ break;
+ case AF_INET6:
+ entry_struct_size = XT_ALIGN(sizeof(struct ip6t_entry));
+ entry_head_size = entry_struct_size + xt_error_target_size;
- entry_head->target_offset = ALIGN(sizeof(struct ipt_entry));
- entry_head->next_offset = entry_head_size;
+ entry6_head = g_try_malloc0(entry_head_size);
+ if (!entry6_head)
+ goto err_head;
- error = (struct error_target *) entry_head->elems;
- g_stpcpy(error->t.u.user.name, IPT_ERROR_TARGET);
- error->t.u.user.target_size = ALIGN(sizeof(struct error_target));
- g_stpcpy(error->error, name);
+ entry6_head->target_offset = entry_struct_size;
+ entry6_head->next_offset = entry_head_size;
- if (iptables_add_entry(table, entry_head, last, -1, -1) < 0)
+ error = (struct xt_error_target *) entry6_head->elems;
+
+ entry.entry6 = entry6_head;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ g_stpcpy(error->target.u.user.name, get_error_target(entry.type));
+ error->target.u.user.target_size = xt_error_target_size;
+ g_stpcpy(error->errorname, name);
+
+ if (iptables_add_entry(table, &entry, last, -1, -1) < 0)
goto err_head;
+ standard_target_size = XT_ALIGN(sizeof(struct ipt_standard_target));
+ entry_return_size = entry_struct_size + standard_target_size;
+
/* tail entry */
- entry_return_size = ALIGN(sizeof(struct ipt_entry))+
- ALIGN(sizeof(struct ipt_standard_target));
- entry_return = g_try_malloc0(entry_return_size);
- if (!entry_return)
- goto err;
+ switch (entry.type) {
+ case AF_INET:
+ entry_return = g_try_malloc0(entry_return_size);
+ if (!entry_return)
+ goto err;
+
+ entry_return->target_offset = entry_struct_size;
+ entry_return->next_offset = entry_return_size;
+
+ standard = (struct ipt_standard_target *) entry_return->elems;
+
+ entry.entry = entry_return;
+ break;
+ case AF_INET6:
+ entry6_return = g_try_malloc0(entry_return_size);
+ if (!entry6_return)
+ goto err;
- entry_return->target_offset = ALIGN(sizeof(struct ipt_entry));
- entry_return->next_offset = entry_return_size;
+ entry6_return->target_offset = entry_struct_size;
+ entry6_return->next_offset = entry_return_size;
- standard = (struct ipt_standard_target *) entry_return->elems;
- standard->target.u.user.target_size =
- ALIGN(sizeof(struct ipt_standard_target));
+ standard = (struct ipt_standard_target *) entry6_return->elems;
+
+ entry.entry6 = entry6_return;
+ break;
+ }
+
+ standard->target.u.user.target_size = standard_target_size;
standard->verdict = XT_RETURN;
- if (iptables_add_entry(table, entry_return, last, -1, -1) < 0)
+ if (iptables_add_entry(table, &entry, last, -1, -1) < 0)
goto err;
return 0;
err:
g_free(entry_return);
+ g_free(entry6_return);
err_head:
g_free(entry_head);
+ g_free(entry6_head);
return -ENOMEM;
}
@@ -691,14 +1130,21 @@ static int iptables_delete_chain(struct connman_iptables *table,
return 0;
}
-static struct ipt_entry *new_rule(struct ipt_ip *ip,
+static struct connman_iptables_entry *new_rule(struct iptables_ip *ip,
const char *target_name, struct xtables_target *xt_t,
struct xtables_rule_match *xt_rm)
{
struct xtables_rule_match *tmp_xt_rm;
- struct ipt_entry *new_entry;
+ struct connman_iptables_entry *new_entry;
size_t match_size, target_size;
+ new_entry = g_try_malloc0(sizeof(struct connman_iptables_entry));
+
+ if (!new_entry)
+ return NULL;
+
+ new_entry->type = ip->type;
+
match_size = 0;
for (tmp_xt_rm = xt_rm; tmp_xt_rm; tmp_xt_rm = tmp_xt_rm->next)
match_size += tmp_xt_rm->match->m->u.match_size;
@@ -706,46 +1152,89 @@ static struct ipt_entry *new_rule(struct ipt_ip *ip,
if (xt_t)
target_size = xt_t->t->u.target_size;
else
- target_size = ALIGN(sizeof(struct xt_standard_target));
-
- new_entry = g_try_malloc0(ALIGN(sizeof(struct ipt_entry)) +
- target_size + match_size);
- if (!new_entry)
- return NULL;
-
- memcpy(&new_entry->ip, ip, sizeof(struct ipt_ip));
-
- new_entry->target_offset = ALIGN(sizeof(struct ipt_entry)) +
- match_size;
- new_entry->next_offset = ALIGN(sizeof(struct ipt_entry)) +
+ target_size = XT_ALIGN(sizeof(struct xt_standard_target));
+
+ switch (ip->type) {
+ case AF_INET:
+ new_entry->entry = g_try_malloc0(
+ XT_ALIGN(sizeof(struct ipt_entry)) +
+ target_size + match_size);
+ if (!new_entry->entry)
+ goto err;
+
+ memcpy(&new_entry->entry->ip, ip->ip, sizeof(struct ipt_ip));
+
+ new_entry->entry->target_offset =
+ XT_ALIGN(sizeof(struct ipt_entry)) +
+ match_size;
+ new_entry->entry->next_offset =
+ XT_ALIGN(sizeof(struct ipt_entry)) +
+ target_size + match_size;
+ break;
+ case AF_INET6:
+ new_entry->entry6 = g_try_malloc0(
+ XT_ALIGN(sizeof(struct ip6t_entry)) +
+ target_size + match_size);
+ if (!new_entry->entry6)
+ goto err;
+
+ memcpy(&new_entry->entry6->ipv6, ip->ip6,
+ sizeof(struct ip6t_ip6));
+
+ new_entry->entry6->target_offset =
+ XT_ALIGN(sizeof(struct ip6t_entry)) +
+ match_size;
+ new_entry->entry6->next_offset =
+ XT_ALIGN(sizeof(struct ip6t_entry)) +
target_size + match_size;
+ break;
+ default:
+ goto err;
+ }
match_size = 0;
for (tmp_xt_rm = xt_rm; tmp_xt_rm;
tmp_xt_rm = tmp_xt_rm->next) {
- memcpy(new_entry->elems + match_size, tmp_xt_rm->match->m,
+
+ switch (new_entry->type) {
+ case AF_INET:
+ memcpy(new_entry->entry->elems + match_size,
+ tmp_xt_rm->match->m,
+ tmp_xt_rm->match->m->u.match_size);
+ break;
+ case AF_INET6:
+ memcpy(new_entry->entry6->elems + match_size,
+ tmp_xt_rm->match->m,
tmp_xt_rm->match->m->u.match_size);
+ break;
+ }
match_size += tmp_xt_rm->match->m->u.match_size;
}
if (xt_t) {
struct xt_entry_target *entry_target;
- entry_target = ipt_get_target(new_entry);
+ entry_target = iptables_entry_get_target(new_entry);
memcpy(entry_target, xt_t->t, target_size);
}
return new_entry;
+
+err:
+ g_free(new_entry);
+
+ return NULL;
}
static void update_hooks(struct connman_iptables *table, GList *chain_head,
- struct ipt_entry *entry)
+ struct connman_iptables_entry *entry)
{
GList *list;
struct connman_iptables_entry *head, *e;
int builtin;
+ u_int16_t next_offset;
- if (!chain_head)
+ if (!table || !chain_head)
return;
head = chain_head->data;
@@ -754,7 +1243,9 @@ static void update_hooks(struct connman_iptables *table, GList *chain_head,
if (builtin < 0)
return;
- table->underflow[builtin] += entry->next_offset;
+ next_offset = iptables_entry_get_next_offset(entry);
+
+ table->underflow[builtin] += next_offset;
for (list = chain_head->next; list; list = list->next) {
e = list->data;
@@ -763,21 +1254,24 @@ static void update_hooks(struct connman_iptables *table, GList *chain_head,
if (builtin < 0)
continue;
- table->hook_entry[builtin] += entry->next_offset;
- table->underflow[builtin] += entry->next_offset;
+ table->hook_entry[builtin] += next_offset;
+ table->underflow[builtin] += next_offset;
}
}
-static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
- struct ipt_ip *ip, const char *chain_name,
+static struct connman_iptables_entry *prepare_rule_inclusion(
+ struct connman_iptables *table,
+ struct iptables_ip *ip,
+ const char *chain_name,
const char *target_name,
struct xtables_target *xt_t,
- int *builtin, struct xtables_rule_match *xt_rm,
+ int *builtin,
+ struct xtables_rule_match *xt_rm,
bool insert)
{
GList *chain_tail, *chain_head;
- struct ipt_entry *new_entry;
struct connman_iptables_entry *head;
+ struct connman_iptables_entry *new_entry;
chain_head = find_chain_head(table, chain_name);
if (!chain_head)
@@ -788,8 +1282,17 @@ static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
return NULL;
new_entry = new_rule(ip, target_name, xt_t, xt_rm);
- if (!new_entry)
- return NULL;
+
+ switch (new_entry->type) {
+ case AF_INET:
+ if (new_entry->entry)
+ break;
+ case AF_INET6:
+ if (new_entry->entry6)
+ break;
+ default:
+ goto err;
+ }
update_hooks(table, chain_head, new_entry);
@@ -807,15 +1310,21 @@ static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
}
return new_entry;
+
+err:
+ g_free(new_entry);
+
+ return NULL;
}
static int iptables_append_rule(struct connman_iptables *table,
- struct ipt_ip *ip, const char *chain_name,
+ struct iptables_ip *ip,
+ const char *chain_name,
const char *target_name,
struct xtables_target *xt_t,
struct xtables_rule_match *xt_rm)
{
- struct ipt_entry *new_entry;
+ struct connman_iptables_entry *new_entry;
int builtin = -1, ret;
GList *chain_tail;
@@ -825,25 +1334,51 @@ static int iptables_append_rule(struct connman_iptables *table,
if (!chain_tail)
return -EINVAL;
- new_entry = prepare_rule_inclusion(table, ip, chain_name,
- target_name, xt_t, &builtin, xt_rm, false);
+ new_entry = prepare_rule_inclusion(table, ip, chain_name, target_name,
+ xt_t, &builtin, xt_rm, false);
+
if (!new_entry)
return -EINVAL;
- ret = iptables_add_entry(table, new_entry, chain_tail->prev, builtin, -1);
+ switch (new_entry->type) {
+ case AF_INET:
+ if (new_entry->entry)
+ break;
+ case AF_INET6:
+ if (new_entry->entry6)
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = iptables_add_entry(table, new_entry, chain_tail->prev,
+ builtin, -1);
if (ret < 0)
- g_free(new_entry);
+ goto err;
+
+ /*
+ * Free only the container, not the content iptables_add_entry()
+ * allocates new containers for entries.
+ */
+ g_free(new_entry);
+
+ return ret;
+
+err:
+ iptables_entry_free(new_entry);
return ret;
}
static int iptables_insert_rule(struct connman_iptables *table,
- struct ipt_ip *ip, const char *chain_name,
+ struct iptables_ip *ip,
+ const char *chain_name,
const char *target_name,
struct xtables_target *xt_t,
struct xtables_rule_match *xt_rm)
{
- struct ipt_entry *new_entry;
+ struct connman_iptables_entry *new_entry;
int builtin = -1, ret;
GList *chain_head;
@@ -853,17 +1388,41 @@ static int iptables_insert_rule(struct connman_iptables *table,
if (!chain_head)
return -EINVAL;
- new_entry = prepare_rule_inclusion(table, ip, chain_name,
- target_name, xt_t, &builtin, xt_rm, true);
+ new_entry = prepare_rule_inclusion(table, ip, chain_name, target_name,
+ xt_t, &builtin, xt_rm, true);
+
if (!new_entry)
return -EINVAL;
+ switch (new_entry->type) {
+ case AF_INET:
+ if (new_entry->entry)
+ break;
+ case AF_INET6:
+ if (new_entry->entry6)
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
if (builtin == -1)
chain_head = chain_head->next;
ret = iptables_add_entry(table, new_entry, chain_head, builtin, -1);
if (ret < 0)
- g_free(new_entry);
+ goto err;
+
+ /*
+ * Free only the container, not the content iptables_add_entry()
+ * allocates new containers for entries.
+ */
+ g_free(new_entry);
+
+ return ret;
+
+err:
+ iptables_entry_free(new_entry);
return ret;
}
@@ -883,6 +1442,38 @@ static bool is_same_ipt_entry(struct ipt_entry *i_e1,
return true;
}
+/* A copy of is_same_ipt_entry with IPv6 structures */
+static bool is_same_ip6t_entry(struct ip6t_entry *i_e1,
+ struct ip6t_entry *i_e2)
+{
+ if (memcmp(&i_e1->ipv6, &i_e2->ipv6, sizeof(struct ip6t_ip6)) != 0)
+ return false;
+
+ if (i_e1->target_offset != i_e2->target_offset)
+ return false;
+
+ if (i_e1->next_offset != i_e2->next_offset)
+ return false;
+
+ return true;
+}
+
+static bool is_same_iptables_entry(struct connman_iptables_entry *e1,
+ struct connman_iptables_entry *e2)
+{
+ if (e1->type != e2->type)
+ return false;
+
+ switch (e1->type) {
+ case AF_INET:
+ return is_same_ipt_entry(e1->entry, e2->entry);
+ case AF_INET6:
+ return is_same_ip6t_entry(e1->entry6, e2->entry6);
+ }
+
+ return false;
+}
+
static bool is_same_target(struct xt_entry_target *xt_e_t1,
struct xt_entry_target *xt_e_t2)
{
@@ -895,7 +1486,12 @@ static bool is_same_target(struct xt_entry_target *xt_e_t1,
g_strcmp0(xt_e_t2->u.user.name, "") == 0) {
/* fallthrough */
return true;
- } else if (g_strcmp0(xt_e_t1->u.user.name, IPT_STANDARD_TARGET) == 0) {
+
+ /*
+ * IPT_STANDARD_TARGET and IP6T_STANDARD_TARGET are defined by
+ * XT_STANDARD_TARGET
+ */
+ } else if (g_strcmp0(xt_e_t1->u.user.name, XT_STANDARD_TARGET) == 0) {
struct xt_standard_target *xt_s_t1;
struct xt_standard_target *xt_s_t2;
@@ -948,7 +1544,8 @@ static bool is_same_match(struct xt_entry_match *xt_e_m1,
}
static GList *find_existing_rule(struct connman_iptables *table,
- struct ipt_ip *ip, const char *chain_name,
+ struct iptables_ip *ip,
+ const char *chain_name,
const char *target_name,
struct xtables_target *xt_t,
GList *matches,
@@ -958,7 +1555,7 @@ static GList *find_existing_rule(struct connman_iptables *table,
struct xt_entry_target *xt_e_t = NULL;
struct xt_entry_match *xt_e_m = NULL;
struct connman_iptables_entry *entry;
- struct ipt_entry *entry_test;
+ struct connman_iptables_entry *entry_test;
int builtin;
chain_head = find_chain_head(table, chain_name);
@@ -973,13 +1570,25 @@ static GList *find_existing_rule(struct connman_iptables *table,
return NULL;
entry_test = new_rule(ip, target_name, xt_t, xt_rm);
- if (!entry_test)
+
+ switch (entry_test->type) {
+ case AF_INET:
+ if (!entry_test->entry)
+ return NULL;
+ break;
+ case AF_INET6:
+ if (!entry_test->entry6)
+ return NULL;
+ break;
+ default:
return NULL;
+ }
if (xt_t)
- xt_e_t = ipt_get_target(entry_test);
+ xt_e_t = iptables_entry_get_target(entry_test);
if (matches)
- xt_e_m = (struct xt_entry_match *)entry_test->elems;
+ xt_e_m = (struct xt_entry_match *)
+ iptables_entry_get_elems(entry_test);
entry = chain_head->data;
builtin = entry->builtin;
@@ -991,18 +1600,16 @@ static GList *find_existing_rule(struct connman_iptables *table,
for (; list != chain_tail->prev; list = list->next) {
struct connman_iptables_entry *tmp;
- struct ipt_entry *tmp_e;
tmp = list->data;
- tmp_e = tmp->entry;
- if (!is_same_ipt_entry(entry_test, tmp_e))
+ if (!is_same_iptables_entry(entry_test, tmp))
continue;
if (xt_t) {
- struct xt_entry_target *tmp_xt_e_t;
+ struct xt_entry_target *tmp_xt_e_t = NULL;
- tmp_xt_e_t = ipt_get_target(tmp_e);
+ tmp_xt_e_t = iptables_entry_get_target(tmp);
if (!is_same_target(tmp_xt_e_t, xt_e_t))
continue;
@@ -1011,7 +1618,8 @@ static GList *find_existing_rule(struct connman_iptables *table,
if (matches) {
struct xt_entry_match *tmp_xt_e_m;
- tmp_xt_e_m = (struct xt_entry_match *)tmp_e->elems;
+ tmp_xt_e_m = (struct xt_entry_match *)
+ iptables_entry_get_elems(tmp);
if (!is_same_match(tmp_xt_e_m, xt_e_m))
continue;
@@ -1020,7 +1628,7 @@ static GList *find_existing_rule(struct connman_iptables *table,
break;
}
- g_free(entry_test);
+ iptables_entry_free(entry_test);
if (list != chain_tail->prev)
return list;
@@ -1029,7 +1637,8 @@ static GList *find_existing_rule(struct connman_iptables *table,
}
static int iptables_delete_rule(struct connman_iptables *table,
- struct ipt_ip *ip, const char *chain_name,
+ struct iptables_ip *ip,
+ const char *chain_name,
const char *target_name,
struct xtables_target *xt_t,
GList *matches,
@@ -1039,7 +1648,6 @@ static int iptables_delete_rule(struct connman_iptables *table,
GList *chain_head, *chain_tail, *list;
int builtin, removed;
-
DBG("table %s chain %s", table->name, chain_name);
removed = 0;
@@ -1053,7 +1661,8 @@ static int iptables_delete_rule(struct connman_iptables *table,
return -EINVAL;
list = find_existing_rule(table, ip, chain_name, target_name,
- xt_t, matches, xt_rm);
+ xt_t, matches, xt_rm);
+
if (!list)
return -EINVAL;
@@ -1129,7 +1738,11 @@ static int iptables_change_policy(struct connman_iptables *table,
return -EINVAL;
entry = chain_tail->prev->data;
- target = ipt_get_target(entry->entry);
+
+ target = iptables_entry_get_target(entry);
+
+ if (!target)
+ return -EINVAL;
t = (struct xt_standard_target *)target;
if (t->verdict != verdict)
@@ -1180,38 +1793,114 @@ static struct ipt_replace *iptables_blob(struct connman_iptables *table)
return r;
}
-static void dump_ip(struct ipt_entry *entry)
+/* A copy of iptables_blob() with IPv6 structures */
+static struct ip6t_replace *ip6tables_blob(struct connman_iptables *table)
{
- struct ipt_ip *ip = &entry->ip;
+ struct ip6t_replace *r;
+ GList *list;
+ struct connman_iptables_entry *e;
+ unsigned char *entry_index;
+
+ r = g_try_malloc0(sizeof(struct ip6t_replace) + table->size);
+ if (!r)
+ return NULL;
+
+ memset(r, 0, sizeof(*r) + table->size);
+
+ r->counters = g_try_malloc0(sizeof(struct xt_counters)
+ * table->old_entries);
+ if (!r->counters) {
+ g_free(r);
+ return NULL;
+ }
+
+ g_stpcpy(r->name, table->info6->name);
+ r->num_entries = table->num_entries;
+ r->size = table->size;
+
+ r->num_counters = table->old_entries;
+ r->valid_hooks = table->info6->valid_hooks;
+
+ memcpy(r->hook_entry, table->hook_entry, sizeof(table->hook_entry));
+ memcpy(r->underflow, table->underflow, sizeof(table->underflow));
+
+ entry_index = (unsigned char *)r->entries;
+ for (list = table->entries; list; list = list->next) {
+ e = list->data;
+
+ memcpy(entry_index, e->entry6, e->entry6->next_offset);
+ entry_index += e->entry6->next_offset;
+ }
+
+ return r;
+}
+
+static void dump_ip(struct connman_iptables_entry *entry)
+{
+ char *iniface, *outiface;
char ip_string[INET6_ADDRSTRLEN];
char ip_mask[INET6_ADDRSTRLEN];
- if (strlen(ip->iniface))
- DBG("\tin %s", ip->iniface);
+ switch (entry->type) {
+ case AF_INET:
+ iniface = entry->entry->ip.iniface;
+ outiface = entry->entry->ip.outiface;
+ break;
+ case AF_INET6:
+ iniface = entry->entry6->ipv6.iniface;
+ outiface = entry->entry6->ipv6.outiface;
+ break;
+ default:
+ return;
+ }
+
+ if (strlen(iniface))
+ DBG("\tin %s", iniface);
- if (strlen(ip->outiface))
- DBG("\tout %s", ip->outiface);
+ if (strlen(outiface))
+ DBG("\tout %s", outiface);
- if (inet_ntop(AF_INET, &ip->src, ip_string, INET6_ADDRSTRLEN) &&
- inet_ntop(AF_INET, &ip->smsk, ip_mask,
+ if (entry->type == AF_INET) {
+ if (inet_ntop(entry->type, &entry->entry->ip.src, ip_string,
+ INET6_ADDRSTRLEN) && inet_ntop(entry->type,
+ &entry->entry->ip.smsk, ip_mask,
INET6_ADDRSTRLEN))
- DBG("\tsrc %s/%s", ip_string, ip_mask);
+ DBG("\tsrc %s/%s", ip_string, ip_mask);
- if (inet_ntop(AF_INET, &ip->dst, ip_string, INET6_ADDRSTRLEN) &&
- inet_ntop(AF_INET, &ip->dmsk, ip_mask,
+ if (inet_ntop(entry->type, &entry->entry->ip.dst, ip_string,
+ INET6_ADDRSTRLEN) && inet_ntop(entry->type,
+ &entry->entry->ip.dmsk, ip_mask,
INET6_ADDRSTRLEN))
- DBG("\tdst %s/%s", ip_string, ip_mask);
-}
+ DBG("\tdst %s/%s", ip_string, ip_mask);
+ }
-static void dump_target(struct ipt_entry *entry)
+ if (entry->type == AF_INET6) {
+ if (inet_ntop(entry->type, &entry->entry6->ipv6.src, ip_string,
+ INET6_ADDRSTRLEN) && inet_ntop(entry->type,
+ &entry->entry6->ipv6.smsk, ip_mask,
+ INET6_ADDRSTRLEN))
+ DBG("\tsrc %s/%s", ip_string, ip_mask);
+ if (inet_ntop(entry->type, &entry->entry6->ipv6.dst, ip_string,
+ INET6_ADDRSTRLEN) && inet_ntop(entry->type,
+ &entry->entry6->ipv6.dmsk, ip_mask,
+ INET6_ADDRSTRLEN))
+ DBG("\tdst %s/%s", ip_string, ip_mask);
+ }
+}
+
+static void dump_target(struct connman_iptables_entry *entry)
{
struct xtables_target *xt_t;
struct xt_entry_target *target;
+ int err;
- target = ipt_get_target(entry);
+ target = iptables_entry_get_target(entry);
- if (!g_strcmp0(target->u.user.name, IPT_STANDARD_TARGET)) {
+ if (!target)
+ return;
+
+ if (!g_strcmp0(target->u.user.name, get_standard_target(entry->type))) {
struct xt_standard_target *t;
t = (struct xt_standard_target *)target;
@@ -1242,13 +1931,34 @@ static void dump_target(struct ipt_entry *entry)
break;
}
- xt_t = xtables_find_target(IPT_STANDARD_TARGET,
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return;
+ }
+
+ xt_t = xtables_find_target(get_standard_target(entry->type),
XTF_LOAD_MUST_SUCCEED);
+ disable_jmp();
+
if (xt_t->print)
xt_t->print(NULL, target, 1);
} else {
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return;
+ }
+
xt_t = xtables_find_target(target->u.user.name, XTF_TRY_LOAD);
+
+ disable_jmp();
+
if (!xt_t) {
DBG("\ttarget %s", target->u.user.name);
return;
@@ -1264,20 +1974,47 @@ static void dump_target(struct ipt_entry *entry)
free(xt_t);
}
-static void dump_match(struct ipt_entry *entry)
+static void dump_match(struct connman_iptables_entry *entry)
{
struct xtables_match *xt_m;
struct xt_entry_match *match;
+ u_int16_t target_offset;
+ int err;
+
+ target_offset = iptables_entry_get_target_offset(entry);
- if (entry->elems == (unsigned char *)entry + entry->target_offset)
+ switch (entry->type) {
+ case AF_INET:
+ if (entry->entry->elems == (unsigned char *)entry->entry +
+ target_offset)
+ return;
+ break;
+ case AF_INET6:
+ if (entry->entry6->elems == (unsigned char *)entry->entry6 +
+ target_offset)
+ return;
+ break;
+ default:
return;
+ }
- match = (struct xt_entry_match *) entry->elems;
+ match = (struct xt_entry_match *) iptables_entry_get_elems(entry);
if (!strlen(match->u.user.name))
return;
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return;
+ }
+
xt_m = xtables_find_match(match->u.user.name, XTF_TRY_LOAD, NULL);
+
+ disable_jmp();
+
if (!xt_m)
goto out;
@@ -1295,33 +2032,48 @@ out:
}
-static int dump_entry(struct ipt_entry *entry, int builtin,
+static int dump_entry(struct connman_iptables_entry *entry, int builtin,
unsigned int hook, size_t size, unsigned int offset,
void *user_data)
{
struct xt_entry_target *target;
+ char *char_entry;
+
+ target = iptables_entry_get_target(entry);
- target = ipt_get_target(entry);
+ if (!target)
+ return -EINVAL;
- if (offset + entry->next_offset == size) {
+ if (offset + iptables_entry_get_next_offset(entry) == size) {
DBG("\tEnd of CHAIN");
return 0;
}
+ switch (entry->type) {
+ case AF_INET:
+ char_entry = (char *)entry->entry;
+ break;
+ case AF_INET6:
+ char_entry = (char *)entry->entry6;
+ break;
+ default:
+ return 0;
+ }
+
if (!g_strcmp0(target->u.user.name, IPT_ERROR_TARGET)) {
DBG("\tUSER CHAIN (%s) match %p target %p",
- target->data, entry->elems,
- (char *)entry + entry->target_offset);
+ target->data, iptables_entry_get_elems(entry),
+ char_entry + iptables_entry_get_target_offset(entry));
return 0;
} else if (builtin >= 0) {
DBG("\tCHAIN (%s) match %p target %p",
- hooknames[builtin], entry->elems,
- (char *)entry + entry->target_offset);
+ hooknames[builtin], iptables_entry_get_elems(entry),
+ char_entry + iptables_entry_get_target_offset(entry));
} else {
DBG("\tRULE match %p target %p",
- entry->elems,
- (char *)entry + entry->target_offset);
+ iptables_entry_get_elems(entry),
+ char_entry + iptables_entry_get_target_offset(entry));
}
dump_match(entry);
@@ -1333,54 +2085,192 @@ static int dump_entry(struct ipt_entry *entry, int builtin,
static void dump_table(struct connman_iptables *table)
{
+ struct connman_iptables_entry entry = { 0 };
+ unsigned int *hook_entry;
+ unsigned int *underflow;
+ unsigned int valid_hooks;
+ unsigned int size;
+
+ hook_entry = iptables_table_get_info_hook_entry(table);
+ underflow = iptables_table_get_info_underflow(table);
+ valid_hooks = iptables_table_get_info_valid_hooks(table);
+ size = iptables_table_get_info_size(table);
+
DBG("%s valid_hooks=0x%08x, num_entries=%u, size=%u",
- table->info->name,
- table->info->valid_hooks, table->info->num_entries,
- table->info->size);
+ iptables_table_get_info_name(table),
+ valid_hooks,
+ iptables_table_get_info_num_entries(table),
+ size);
DBG("entry hook: pre/in/fwd/out/post %d/%d/%d/%d/%d",
- table->info->hook_entry[NF_IP_PRE_ROUTING],
- table->info->hook_entry[NF_IP_LOCAL_IN],
- table->info->hook_entry[NF_IP_FORWARD],
- table->info->hook_entry[NF_IP_LOCAL_OUT],
- table->info->hook_entry[NF_IP_POST_ROUTING]);
+ hook_entry[NF_IP_PRE_ROUTING],
+ hook_entry[NF_IP_LOCAL_IN],
+ hook_entry[NF_IP_FORWARD],
+ hook_entry[NF_IP_LOCAL_OUT],
+ hook_entry[NF_IP_POST_ROUTING]);
DBG("underflow: pre/in/fwd/out/post %d/%d/%d/%d/%d",
- table->info->underflow[NF_IP_PRE_ROUTING],
- table->info->underflow[NF_IP_LOCAL_IN],
- table->info->underflow[NF_IP_FORWARD],
- table->info->underflow[NF_IP_LOCAL_OUT],
- table->info->underflow[NF_IP_POST_ROUTING]);
+ underflow[NF_IP_PRE_ROUTING],
+ underflow[NF_IP_LOCAL_IN],
+ underflow[NF_IP_FORWARD],
+ underflow[NF_IP_LOCAL_OUT],
+ underflow[NF_IP_POST_ROUTING]);
+
+ entry.type = table->type;
+
+ switch (table->type) {
+ case AF_INET:
+ entry.entry = table->blob_entries->entrytable;
+ break;
+ case AF_INET6:
+ entry.entry6 = table->blob_entries6->entrytable;
+ }
+
+ iterate_entries(&entry,
+ valid_hooks,
+ hook_entry,
+ underflow,
+ size,
+ print_entry, dump_entry);
+}
+
+static const char *iptables_replace_get_name(struct iptables_replace *replace)
+{
+ if (!replace)
+ return NULL;
+
+ switch (replace->type) {
+ case AF_INET:
+ return replace->r->name;
+ case AF_INET6:
+ return replace->r6->name;
+ }
+
+ return NULL;
+}
+
+static unsigned int iptables_replace_get_valid_hooks(
+ struct iptables_replace *replace)
+{
+ if (!replace)
+ return 0;
+
+ switch (replace->type) {
+ case AF_INET:
+ return replace->r->valid_hooks;
+ case AF_INET6:
+ return replace->r6->valid_hooks;
+ }
+
+ return 0;
+}
+
+static unsigned int iptables_replace_get_num_entries(
+ struct iptables_replace *replace)
+{
+ if (!replace)
+ return 0;
+
+ switch (replace->type) {
+ case AF_INET:
+ return replace->r->num_entries;
+ case AF_INET6:
+ return replace->r6->num_entries;
+ }
+
+ return 0;
+}
+
+static unsigned int *iptables_replace_get_hook_entry(
+ struct iptables_replace *replace)
+{
+ if (!replace)
+ return NULL;
+
+ switch (replace->type) {
+ case AF_INET:
+ return replace->r->hook_entry;
+ case AF_INET6:
+ return replace->r6->hook_entry;
+ }
+
+ return NULL;
+}
+
+static unsigned int *iptables_replace_get_underflow(
+ struct iptables_replace *replace)
+{
+ if (!replace)
+ return NULL;
- iterate_entries(table->blob_entries->entrytable,
- table->info->valid_hooks,
- table->info->hook_entry,
- table->info->underflow,
- table->blob_entries->size,
- print_entry, dump_entry);
+ switch (replace->type) {
+ case AF_INET:
+ return replace->r->underflow;
+ case AF_INET6:
+ return replace->r6->underflow;
+ }
+
+ return NULL;
}
-static void dump_ipt_replace(struct ipt_replace *repl)
+static unsigned int iptables_replace_get_size(struct iptables_replace *replace)
{
+ if (!replace)
+ return 0;
+
+ switch (replace->type) {
+ case AF_INET:
+ return replace->r->size;
+ case AF_INET6:
+ return replace->r6->size;
+ }
+
+ return 0;
+}
+
+static void dump_replace(struct iptables_replace *repl)
+{
+ struct connman_iptables_entry entry = { 0 };
+ unsigned int *hook_entry;
+ unsigned int *underflow;
+ unsigned int valid_hooks;
+ unsigned int size;
+
+ hook_entry = iptables_replace_get_hook_entry(repl);
+ underflow = iptables_replace_get_underflow(repl);
+ valid_hooks = iptables_replace_get_valid_hooks(repl);
+ size = iptables_replace_get_size(repl);
+
+ switch (repl->type) {
+ case AF_INET:
+ entry.entry = repl->r->entries;
+ break;
+ case AF_INET6:
+ entry.entry6 = repl->r6->entries;
+ break;
+ default:
+ return;
+ }
+
DBG("%s valid_hooks 0x%08x num_entries %u size %u",
- repl->name, repl->valid_hooks, repl->num_entries,
- repl->size);
+ iptables_replace_get_name(repl),
+ valid_hooks,
+ iptables_replace_get_num_entries(repl), size);
DBG("entry hook: pre/in/fwd/out/post %d/%d/%d/%d/%d",
- repl->hook_entry[NF_IP_PRE_ROUTING],
- repl->hook_entry[NF_IP_LOCAL_IN],
- repl->hook_entry[NF_IP_FORWARD],
- repl->hook_entry[NF_IP_LOCAL_OUT],
- repl->hook_entry[NF_IP_POST_ROUTING]);
+ hook_entry[NF_IP_PRE_ROUTING],
+ hook_entry[NF_IP_LOCAL_IN],
+ hook_entry[NF_IP_FORWARD],
+ hook_entry[NF_IP_LOCAL_OUT],
+ hook_entry[NF_IP_POST_ROUTING]);
DBG("underflow: pre/in/fwd/out/post %d/%d/%d/%d/%d",
- repl->underflow[NF_IP_PRE_ROUTING],
- repl->underflow[NF_IP_LOCAL_IN],
- repl->underflow[NF_IP_FORWARD],
- repl->underflow[NF_IP_LOCAL_OUT],
- repl->underflow[NF_IP_POST_ROUTING]);
+ underflow[NF_IP_PRE_ROUTING],
+ underflow[NF_IP_LOCAL_IN],
+ underflow[NF_IP_FORWARD],
+ underflow[NF_IP_LOCAL_OUT],
+ underflow[NF_IP_POST_ROUTING]);
- iterate_entries(repl->entries, repl->valid_hooks,
- repl->hook_entry, repl->underflow,
- repl->size, print_entry, dump_entry);
+ iterate_entries(&entry, valid_hooks, hook_entry, underflow,
+ size, print_entry, dump_entry);
}
static int iptables_get_entries(struct connman_iptables *table)
@@ -1388,10 +2278,26 @@ static int iptables_get_entries(struct connman_iptables *table)
socklen_t entry_size;
int err;
- entry_size = sizeof(struct ipt_get_entries) + table->info->size;
+ switch (table->type) {
+ case AF_INET:
+ entry_size = sizeof(struct ipt_get_entries) + table->info->size;
+
+ err = getsockopt(table->ipt_sock, IPPROTO_IP,
+ IPT_SO_GET_ENTRIES, table->blob_entries,
+ &entry_size);
+ break;
+ case AF_INET6:
+ entry_size = sizeof(struct ip6t_get_entries) +
+ table->info6->size;
+
+ err = getsockopt(table->ipt_sock, IPPROTO_IPV6,
+ IP6T_SO_GET_ENTRIES, table->blob_entries6,
+ &entry_size);
+ break;
+ default:
+ return -EINVAL;
+ }
- err = getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_ENTRIES,
- table->blob_entries, &entry_size);
if (err < 0)
return -errno;
@@ -1399,12 +2305,31 @@ static int iptables_get_entries(struct connman_iptables *table)
}
static int iptables_replace(struct connman_iptables *table,
- struct ipt_replace *r)
+ struct iptables_replace *r)
{
int err;
- err = setsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_SET_REPLACE, r,
- sizeof(*r) + r->size);
+ switch (r->type) {
+ case AF_INET:
+ if (!r->r)
+ return -EINVAL;
+
+ err = setsockopt(table->ipt_sock, IPPROTO_IP,
+ IPT_SO_SET_REPLACE, r->r,
+ sizeof(*r->r) + r->r->size);
+ break;
+ case AF_INET6:
+ if (!r->r6)
+ return -EINVAL;
+
+ err = setsockopt(table->ipt_sock, IPPROTO_IPV6,
+ IP6T_SO_SET_REPLACE, r->r6,
+ sizeof(*r->r6) + r->r6->size);
+ break;
+ default:
+ return -EINVAL;
+ }
+
if (err < 0)
return -errno;
@@ -1415,29 +2340,63 @@ static int iptables_add_counters(struct connman_iptables *table,
struct xt_counters_info *c)
{
int err;
+ int level;
+ int optname;
+
+ switch (table->type) {
+ case AF_INET:
+ level = IPPROTO_IP;
+ optname = IPT_SO_SET_ADD_COUNTERS;
+ break;
+ case AF_INET6:
+ level = IPPROTO_IPV6;
+ optname = IP6T_SO_SET_ADD_COUNTERS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = setsockopt(table->ipt_sock, level, optname, c,
+ sizeof(*c) + sizeof(struct xt_counters) * c->num_counters);
- 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)
+static int add_entry(struct connman_iptables_entry *entry, int builtin,
+ unsigned int hook, size_t size, unsigned offset,
+ void *user_data)
{
struct connman_iptables *table = user_data;
- struct ipt_entry *new_entry;
-
- new_entry = g_try_malloc0(entry->next_offset);
- if (!new_entry)
- return -ENOMEM;
-
- memcpy(new_entry, entry, entry->next_offset);
+ struct connman_iptables_entry new_entry = { 0 };
+ u_int16_t next_offset;
+
+ new_entry.type = entry->type;
+ next_offset = iptables_entry_get_next_offset(entry);
+
+ switch (entry->type) {
+ case AF_INET:
+ new_entry.entry = g_try_malloc0(next_offset);
+ if (!new_entry.entry)
+ return -ENOMEM;
+
+ memcpy(new_entry.entry, entry->entry, next_offset);
+ break;
+ case AF_INET6:
+ new_entry.entry6 = g_try_malloc0(next_offset);
+ if (!new_entry.entry6)
+ return -ENOMEM;
- return iptables_add_entry(table, new_entry, NULL, builtin,
- table->num_entries);
+ memcpy(new_entry.entry6, entry->entry6, next_offset);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return iptables_add_entry(table, &new_entry, NULL, builtin,
+ table->num_entries);
}
static void table_cleanup(struct connman_iptables *table)
@@ -1454,32 +2413,60 @@ static void table_cleanup(struct connman_iptables *table)
for (list = table->entries; list; list = list->next) {
entry = list->data;
- g_free(entry->entry);
- g_free(entry);
+ iptables_entry_free(entry);
}
g_list_free(table->entries);
g_free(table->name);
- g_free(table->info);
- g_free(table->blob_entries);
+
+ if (table->type == AF_INET) {
+ g_free(table->info);
+ g_free(table->blob_entries);
+ }
+
+ if (table->type == AF_INET6) {
+ g_free(table->info6);
+ g_free(table->blob_entries6);
+ }
+
g_free(table);
}
-static struct connman_iptables *iptables_init(const char *table_name)
+static int setup_xtables(int type);
+static void reset_xtables();
+
+static struct connman_iptables *iptables_init(int type, const char *table_name)
{
struct connman_iptables *table = NULL;
+ struct connman_iptables_entry entry = { 0 };
+ char *iptables_mod = NULL;
char *module = NULL;
socklen_t s;
- DBG("%s", table_name);
+ switch(type) {
+ case AF_INET:
+ iptables_mod = g_strdup("ip_tables");
+ module = g_strconcat("iptable_", table_name, NULL);
+ break;
+ case AF_INET6:
+ iptables_mod = g_strdup("ip6_tables");
+ module = g_strconcat("ip6table_", table_name, NULL);
+ break;
+ default:
+ return NULL;
+ }
- if (xtables_insmod("ip_tables", NULL, TRUE) != 0)
- DBG("ip_tables module loading gives error but trying anyway");
+ DBG("%d %s", type, table_name);
- module = g_strconcat("iptable_", table_name, NULL);
- if (!module)
+ if (setup_xtables(type))
return NULL;
+ if (xtables_insmod(iptables_mod, NULL, TRUE) != 0)
+ DBG("%s module loading gives error but trying anyway",
+ iptables_mod);
+
+ g_free(iptables_mod);
+
if (xtables_insmod(module, NULL, TRUE) != 0)
DBG("%s module loading gives error but trying anyway", module);
@@ -1489,55 +2476,112 @@ static struct connman_iptables *iptables_init(const char *table_name)
if (!table)
return NULL;
- table->info = g_try_new0(struct ipt_getinfo, 1);
- if (!table->info)
- goto err;
+ table->type = entry.type = type;
- table->ipt_sock = socket(AF_INET, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
+ table->ipt_sock = socket(type, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
if (table->ipt_sock < 0)
goto err;
- s = sizeof(*table->info);
- g_stpcpy(table->info->name, table_name);
- if (getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_INFO,
- table->info, &s) < 0) {
- connman_error("iptables support missing error %d (%s)", errno,
- strerror(errno));
- goto err;
- }
+ switch (type) {
+ case AF_INET:
+ table->info = g_try_new0(struct ipt_getinfo, 1);
+ if (!table->info)
+ goto err;
- table->blob_entries = g_try_malloc0(sizeof(struct ipt_get_entries) +
- table->info->size);
- if (!table->blob_entries)
- goto err;
+ s = sizeof(*table->info);
+ g_stpcpy(table->info->name, table_name);
+
+ if (getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_INFO,
+ table->info, &s) < 0) {
+ connman_error("iptables support missing error %d (%s)",
+ errno, strerror(errno));
+ goto err;
+ }
+
+ table->blob_entries = g_try_malloc0(
+ sizeof(struct ipt_get_entries) +
+ table->info->size);
+ if (!table->blob_entries)
+ goto err;
- g_stpcpy(table->blob_entries->name, table_name);
- table->blob_entries->size = table->info->size;
+ g_stpcpy(table->blob_entries->name, table_name);
+ table->blob_entries->size = table->info->size;
+
+ break;
+ case AF_INET6:
+ table->info6 = g_try_new0(struct ip6t_getinfo, 1);
+ if (!table->info6)
+ goto err;
+
+ s = sizeof(*table->info6);
+ g_stpcpy(table->info6->name, table_name);
+
+ if (getsockopt(table->ipt_sock, IPPROTO_IPV6, IP6T_SO_GET_INFO,
+ table->info6, &s) < 0) {
+ connman_error("ip6tables support missing error %d (%s)",
+ errno, strerror(errno));
+ goto err;
+ }
+
+ table->blob_entries6 = g_try_malloc0(
+ sizeof(struct ip6t_get_entries) +
+ table->info6->size);
+ if (!table->blob_entries6)
+ goto err;
+
+ g_stpcpy(table->blob_entries6->name, table_name);
+ table->blob_entries6->size = table->info6->size;
+
+ break;
+ }
if (iptables_get_entries(table) < 0)
goto err;
table->num_entries = 0;
- table->old_entries = table->info->num_entries;
table->size = 0;
- memcpy(table->underflow, table->info->underflow,
- sizeof(table->info->underflow));
- memcpy(table->hook_entry, table->info->hook_entry,
- sizeof(table->info->hook_entry));
+ switch (type) {
+ case AF_INET:
+ table->old_entries = table->info->num_entries;
+
+ memcpy(table->underflow, table->info->underflow,
+ sizeof(table->info->underflow));
+ memcpy(table->hook_entry, table->info->hook_entry,
+ sizeof(table->info->hook_entry));
- iterate_entries(table->blob_entries->entrytable,
- table->info->valid_hooks, table->info->hook_entry,
- table->info->underflow, table->blob_entries->size,
- add_entry, table);
+ entry.entry = table->blob_entries->entrytable;
+ break;
+ case AF_INET6:
+ table->old_entries = table->info6->num_entries;
+
+ memcpy(table->underflow, table->info6->underflow,
+ sizeof(table->info6->underflow));
+ memcpy(table->hook_entry, table->info6->hook_entry,
+ sizeof(table->info6->hook_entry));
+
+ entry.entry6 = table->blob_entries6->entrytable;
+ break;
+ }
+
+ iterate_entries(&entry,
+ iptables_table_get_info_valid_hooks(table),
+ iptables_table_get_info_hook_entry(table),
+ iptables_table_get_info_underflow(table),
+ iptables_table_get_entries_size(table),
+ add_entry,
+ table);
if (debug_enabled)
dump_table(table);
+ reset_xtables();
+
return table;
err:
table_cleanup(table);
+ reset_xtables();
return NULL;
}
@@ -1559,13 +2603,77 @@ static struct option iptables_opts[] = {
{.name = "out-interface", .has_arg = 1, .val = 'o'},
{.name = "source", .has_arg = 1, .val = 's'},
{.name = "table", .has_arg = 1, .val = 't'},
+ {.name = "protocol", .has_arg = 1, .val = 'p'},
{NULL},
};
+void iptables_exit(enum xtables_exittype status, const char *msg, ...)
+ __attribute__((noreturn, format(printf,2,3)));
+
+void iptables_exit(enum xtables_exittype status, const char *msg, ...)
+{
+ va_list args;
+ gchar str[256] = { 0 };
+
+ switch (status) {
+ case OTHER_PROBLEM:
+ DBG("OTHER_PROBLEM");
+ break;
+ case PARAMETER_PROBLEM:
+ DBG("PARAMETER_PROBLEM");
+ break;
+ case VERSION_PROBLEM:
+ DBG("VERSION_PROBLEM");
+ break;
+ case RESOURCE_PROBLEM:
+ DBG("RESOURCE_PROBLEM");
+ break;
+ case XTF_ONLY_ONCE:
+ DBG("XTF_ONLY_ONCE");
+ break;
+ case XTF_NO_INVERT:
+ DBG("XTF_NO_INVERT");
+ break;
+ case XTF_BAD_VALUE:
+ DBG("XTF_BAD_VALUE");
+ break;
+ case XTF_ONE_ACTION:
+ DBG("XTF_ONE_ACTION");
+ break;
+ }
+
+ va_start(args, msg);
+ vsnprintf(str, 256, msg, args);
+ va_end(args);
+
+ connman_error("iptables rule error: %s", str);
+
+ if (can_jmp()) {
+ DBG("calling longjmp()");
+ /* enum xtables_exittype begins from 1 */
+ longjmp(env_state, status);
+ }
+
+ connman_error("exit because of iptables error");
+
+ exit(status);
+}
+
struct xtables_globals iptables_globals = {
.option_offset = 0,
.opts = iptables_opts,
.orig_opts = iptables_opts,
+ .exit_err = iptables_exit,
+#if XTABLES_VERSION_CODE > 10
+ .compat_rev = xtables_compatible_revision,
+#endif
+};
+
+struct xtables_globals ip6tables_globals = {
+ .option_offset = 0,
+ .opts = iptables_opts,
+ .orig_opts = iptables_opts,
+ .exit_err = iptables_exit,
#if XTABLES_VERSION_CODE > 10
.compat_rev = xtables_compatible_revision,
#endif
@@ -1578,9 +2686,15 @@ static struct xtables_target *prepare_target(struct connman_iptables *table,
bool is_builtin, is_user_defined;
GList *chain_head = NULL;
size_t target_size;
+ int err;
is_builtin = false;
is_user_defined = false;
+
+ DBG("target %s", target_name);
+
+ if (!table)
+ return NULL;
if (is_builtin_target(target_name))
is_builtin = true;
@@ -1590,16 +2704,37 @@ static struct xtables_target *prepare_target(struct connman_iptables *table,
is_user_defined = true;
}
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return NULL;
+ }
+
if (is_builtin || is_user_defined)
- xt_t = xtables_find_target(IPT_STANDARD_TARGET,
+ xt_t = xtables_find_target(get_standard_target(table->type),
XTF_LOAD_MUST_SUCCEED);
- else
+ else
xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
+ disable_jmp();
+
if (!xt_t)
return NULL;
- target_size = ALIGN(sizeof(struct ipt_entry_target)) + xt_t->size;
+ switch (table->type) {
+ case AF_INET:
+ target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
+ xt_t->size;
+ break;
+ case AF_INET6:
+ target_size = XT_ALIGN(sizeof(struct ip6t_entry_target)) +
+ xt_t->size;
+ break;
+ default:
+ return NULL;
+ }
xt_t->t = g_try_malloc0(target_size);
if (!xt_t->t)
@@ -1611,7 +2746,8 @@ static struct xtables_target *prepare_target(struct connman_iptables *table,
struct xt_standard_target *target;
target = (struct xt_standard_target *)(xt_t->t);
- g_stpcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
+ g_stpcpy(target->target.u.user.name,
+ get_standard_target(table->type));
if (is_builtin)
target->verdict = target_to_verdict(target_name);
@@ -1628,24 +2764,51 @@ static struct xtables_target *prepare_target(struct connman_iptables *table,
xt_t->init(xt_t->t);
}
- if (xt_t->x6_options)
- iptables_globals.opts =
- xtables_options_xfrm(
- iptables_globals.orig_opts,
- iptables_globals.opts,
- xt_t->x6_options,
- &xt_t->option_offset);
- else
- iptables_globals.opts =
- xtables_merge_options(
- iptables_globals.orig_opts,
- iptables_globals.opts,
- xt_t->extra_opts,
- &xt_t->option_offset);
+ switch (table->type) {
+ case AF_INET:
+ if (xt_t->x6_options)
+ iptables_globals.opts =
+ xtables_options_xfrm(
+ iptables_globals.orig_opts,
+ iptables_globals.opts,
+ xt_t->x6_options,
+ &xt_t->option_offset);
+ else
+ iptables_globals.opts =
+ xtables_merge_options(
+ iptables_globals.orig_opts,
+ iptables_globals.opts,
+ xt_t->extra_opts,
+ &xt_t->option_offset);
+
+ if (!iptables_globals.opts) {
+ g_free(xt_t->t);
+ xt_t = NULL;
+ }
+
+ break;
+ case AF_INET6:
+ if (xt_t->x6_options)
+ ip6tables_globals.opts =
+ xtables_options_xfrm(
+ ip6tables_globals.orig_opts,
+ ip6tables_globals.opts,
+ xt_t->x6_options,
+ &xt_t->option_offset);
+ else
+ ip6tables_globals.opts =
+ xtables_merge_options(
+ ip6tables_globals.orig_opts,
+ ip6tables_globals.opts,
+ xt_t->extra_opts,
+ &xt_t->option_offset);
+
+ if (!ip6tables_globals.opts) {
+ g_free(xt_t->t);
+ xt_t = NULL;
+ }
- if (!iptables_globals.opts) {
- g_free(xt_t->t);
- xt_t = NULL;
+ break;
}
return xt_t;
@@ -1657,12 +2820,35 @@ static struct xtables_match *prepare_matches(struct connman_iptables *table,
{
struct xtables_match *xt_m;
size_t match_size;
+ int err;
+
+ if (!table || !match_name)
+ return NULL;
+
+ enable_jmp();
- if (!match_name)
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
return NULL;
+ }
xt_m = xtables_find_match(match_name, XTF_LOAD_MUST_SUCCEED, xt_rm);
- match_size = ALIGN(sizeof(struct ipt_entry_match)) + xt_m->size;
+
+ disable_jmp();
+
+ switch (table->type) {
+ case AF_INET:
+ match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
+ xt_m->size;
+ break;
+ case AF_INET6:
+ match_size = XT_ALIGN(sizeof(struct ip6t_entry_match)) +
+ xt_m->size;
+ break;
+ default:
+ return NULL;
+ }
xt_m->m = g_try_malloc0(match_size);
if (!xt_m->m)
@@ -1675,28 +2861,59 @@ static struct xtables_match *prepare_matches(struct connman_iptables *table,
if (xt_m->init)
xt_m->init(xt_m->m);
- if (xt_m->x6_options)
- iptables_globals.opts =
- xtables_options_xfrm(
- iptables_globals.orig_opts,
- iptables_globals.opts,
- xt_m->x6_options,
- &xt_m->option_offset);
- else
+ switch (table->type) {
+ case AF_INET:
+ if (xt_m->x6_options)
+ iptables_globals.opts =
+ xtables_options_xfrm(
+ iptables_globals.orig_opts,
+ iptables_globals.opts,
+ xt_m->x6_options,
+ &xt_m->option_offset);
+ else
iptables_globals.opts =
- xtables_merge_options(
- iptables_globals.orig_opts,
- iptables_globals.opts,
- xt_m->extra_opts,
- &xt_m->option_offset);
+ xtables_merge_options(
+ iptables_globals.orig_opts,
+ iptables_globals.opts,
+ xt_m->extra_opts,
+ &xt_m->option_offset);
- if (!iptables_globals.opts) {
- g_free(xt_m->m);
+ if (!iptables_globals.opts) {
+ g_free(xt_m->m);
+
+ if (xt_m == xt_m->next)
+ free(xt_m);
+
+ xt_m = NULL;
+ }
- if (xt_m == xt_m->next)
- free(xt_m);
+ break;
+ case AF_INET6:
+ if (xt_m->x6_options)
+ ip6tables_globals.opts =
+ xtables_options_xfrm(
+ ip6tables_globals.orig_opts,
+ ip6tables_globals.opts,
+ xt_m->x6_options,
+ &xt_m->option_offset);
+ else
+ ip6tables_globals.opts =
+ xtables_merge_options(
+ ip6tables_globals.orig_opts,
+ ip6tables_globals.opts,
+ xt_m->extra_opts,
+ &xt_m->option_offset);
+
+ if (!ip6tables_globals.opts) {
+ g_free(xt_m->m);
+
+ if (xt_m == xt_m->next)
+ free(xt_m);
+
+ xt_m = NULL;
+ }
- xt_m = NULL;
+ break;
}
return xt_m;
@@ -1721,12 +2938,14 @@ static int parse_ip_and_mask(const char *str, struct in_addr *ip,
if (tokens[1]) {
prefixlength = strtol(tokens[1], NULL, 10);
- if (prefixlength > 31) {
+ if (prefixlength > 32) {
err = -1;
goto out;
+ } else if (prefixlength == 32) {
+ tmp = 0xffffffff;
+ } else {
+ tmp = ~(0xffffffff >> prefixlength);
}
-
- tmp = ~(0xffffffff >> prefixlength);
} else {
tmp = 0xffffffff;
}
@@ -1740,35 +2959,96 @@ out:
return err;
}
-static struct connman_iptables *get_table(const char *table_name)
+static int parse_ipv6_and_mask(const char *str, struct in6_addr *ip,
+ struct in6_addr *mask)
{
- struct connman_iptables *table;
+ char **tokens;
+ uint32_t prefixlength;
+ struct in6_addr in6;
+ int i, j;
+ int err;
+
+ tokens = g_strsplit(str, "/", 2);
+ if (!tokens)
+ return -1;
+
+ if (!inet_pton(AF_INET6, tokens[0], ip)) {
+ err = -1;
+ goto out;
+ }
+
+ if (tokens[1]) {
+ prefixlength = strtol(tokens[1], NULL, 10);
+ if (prefixlength > 128) {
+ err = -1;
+ goto out;
+ }
+ } else {
+ prefixlength = 128;
+ }
+
+ /*
+ * This part was adapted from (no need to re-invent the wheel):
+ * https://gitlab.com/ipcalc/ipcalc/blob/master/ipcalc.c#L733
+ */
+ memset(&in6, 0, sizeof(struct in6_addr));
+
+ for (i = prefixlength, j = 0; i > 0; i -= 8, j++) {
+ if (i >= 8)
+ in6.s6_addr[j] = 0xff;
+ else
+ in6.s6_addr[j] = (unsigned long)(0xffU << (8 - i));
+ }
+
+ memcpy(mask, &in6, sizeof(struct in6_addr));
+
+ for (i = 0; i < 16 ; i++)
+ ip->s6_addr[i] = ip->s6_addr[i] & mask->s6_addr[i];
+
+ err = 0;
+out:
+ g_strfreev(tokens);
+
+ return err;
+}
+
+static struct connman_iptables *get_table(int type, const char *table_name)
+{
+ struct connman_iptables *table = NULL;
if (!table_name)
table_name = "filter";
- table = g_hash_table_lookup(table_hash, table_name);
+ table = hash_table_lookup(type, table_name);
+
if (table)
return table;
- table = iptables_init(table_name);
+ table = iptables_init(type, table_name);
+
if (!table)
return NULL;
+ if (table->name)
+ g_free(table->name);
+
table->name = g_strdup(table_name);
- g_hash_table_replace(table_hash, table->name, table);
+
+ hash_table_replace(type, table->name, table);
return table;
}
struct parse_context {
+ int type;
int argc;
char **argv;
struct ipt_ip *ip;
+ struct ip6t_ip6 *ipv6;
struct xtables_target *xt_t;
GList *xt_m;
struct xtables_rule_match *xt_rm;
- int proto;
+ uint16_t proto;
};
static int prepare_getopt_args(const char *str, struct parse_context *ctx)
@@ -1809,13 +3089,34 @@ static int parse_xt_modules(int c, bool invert,
struct xtables_match *m;
struct xtables_rule_match *rm;
struct ipt_entry fw;
+ struct ip6t_entry fw6;
+ int err;
+
+ switch (ctx->type) {
+ case AF_INET:
+ 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;
+ break;
+ case AF_INET6:
+ memset(&fw6, 0, sizeof(fw6));
+
+ if (ctx->proto == 0)
+ ctx->proto = IPPROTO_IPV6;
+
+ fw6.ipv6.proto = ctx->proto;
- memset(&fw, 0, sizeof(fw));
+ /* Flags must be set for IPv6 if protocol is set. */
+ fw6.ipv6.flags |= IP6T_F_PROTO;
- /* The SNAT parser wants to know the protocol. */
- if (ctx->proto == 0)
- ctx->proto = IPPROTO_IP;
- fw.ip.proto = ctx->proto;
+ break;
+ default:
+ return 0;
+ }
for (rm = ctx->xt_rm; rm; rm = rm->next) {
if (rm->completed != 0)
@@ -1831,7 +3132,24 @@ static int parse_xt_modules(int c, bool invert,
+ XT_OPTION_OFFSET_SCALE)
continue;
- xtables_option_mpcall(c, ctx->argv, invert, m, &fw);
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return -EINVAL;
+ }
+
+ switch (ctx->type) {
+ case AF_INET:
+ xtables_option_mpcall(c, ctx->argv, invert, m, &fw);
+ break;
+ case AF_INET6:
+ xtables_option_mpcall(c, ctx->argv, invert, m, &fw6);
+ break;
+ }
+
+ disable_jmp();
}
if (!ctx->xt_t)
@@ -1845,7 +3163,24 @@ 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, &fw);
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return -EINVAL;
+ }
+
+ switch (ctx->type) {
+ case AF_INET:
+ xtables_option_tpcall(c, ctx->argv, invert, ctx->xt_t, &fw);
+ break;
+ case AF_INET6:
+ xtables_option_tpcall(c, ctx->argv, invert, ctx->xt_t, &fw6);
+ break;
+ }
+
+ disable_jmp();
return 0;
}
@@ -1853,13 +3188,35 @@ static int parse_xt_modules(int c, bool invert,
static int final_check_xt_modules(struct parse_context *ctx)
{
struct xtables_rule_match *rm;
+ int err;
+
+ for (rm = ctx->xt_rm; rm; rm = rm->next) {
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return -EINVAL;
+ }
- for (rm = ctx->xt_rm; rm; rm = rm->next)
xtables_option_mfcall(rm->match);
+ disable_jmp();
+ }
+
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value %d", err);
+ disable_jmp();
+ return -EINVAL;
+ }
+
if (ctx->xt_t)
xtables_option_tfcall(ctx->xt_t);
+ disable_jmp();
+
return 0;
}
@@ -1946,9 +3303,28 @@ static int parse_rule_spec(struct connman_iptables *table,
bool invert = false;
int len, c, err;
- ctx->ip = g_try_new0(struct ipt_ip, 1);
- if (!ctx->ip)
- return -ENOMEM;
+ if (ctx->type != table->type) {
+ DBG("ctx->type %d does not match table->type %d", ctx->type,
+ table->type);
+ return -EINVAL;
+ }
+
+ switch (ctx->type) {
+ case AF_INET:
+ ctx->ip = g_try_new0(struct ipt_ip, 1);
+ if (!ctx->ip)
+ return -ENOMEM;
+
+ break;
+ case AF_INET6:
+ ctx->ipv6 = g_try_new0(struct ip6t_ip6, 1);
+ if (!ctx->ipv6)
+ return -ENOMEM;
+
+ break;
+ default:
+ return -EINVAL;
+ }
/*
* Tell getopt_long not to generate error messages for unknown
@@ -1958,29 +3334,58 @@ static int parse_rule_spec(struct connman_iptables *table,
optind = 0;
while ((c = getopt_long(ctx->argc, ctx->argv,
- "-:d:i:o:s:m:j:",
- iptables_globals.opts, NULL)) != -1) {
+ "-:d:i:o:s:m:j:p:",
+ ctx->type == AF_INET ?
+ iptables_globals.opts :
+ ip6tables_globals.opts,
+ NULL)) != -1) {
switch (c) {
case 's':
- /* Source specification */
- if (!parse_ip_and_mask(optarg,
- &ctx->ip->src,
- &ctx->ip->smsk))
- break;
+ if (ctx->type == AF_INET) {
+ /* Source specification */
+ if (!parse_ip_and_mask(optarg,
+ &ctx->ip->src,
+ &ctx->ip->smsk))
+ break;
+
+ if (invert)
+ ctx->ip->invflags |= IPT_INV_SRCIP;
+ }
+
+ if (ctx->type == AF_INET6) {
+ if (!parse_ipv6_and_mask(optarg,
+ &ctx->ipv6->src,
+ &ctx->ipv6->smsk))
+ break;
- if (invert)
- ctx->ip->invflags |= IPT_INV_SRCIP;
+ if (invert)
+ ctx->ipv6->invflags |= IP6T_INV_SRCIP;
+ }
break;
case 'd':
- /* Destination specification */
- if (!parse_ip_and_mask(optarg,
- &ctx->ip->dst,
- &ctx->ip->dmsk))
- break;
+ if (ctx->type == AF_INET) {
+ /* Destination specification */
+ if (!parse_ip_and_mask(optarg,
+ &ctx->ip->dst,
+ &ctx->ip->dmsk))
+ break;
+
+ if (invert)
+ ctx->ip->invflags |= IPT_INV_DSTIP;
+ }
+
+ if (ctx->type == AF_INET6) {
+ /* Destination specification */
+ if (!parse_ipv6_and_mask(optarg,
+ &ctx->ipv6->dst,
+ &ctx->ipv6->dmsk))
+ break;
- if (invert)
- ctx->ip->invflags |= IPT_INV_DSTIP;
+ if (invert)
+ ctx->ip->invflags |= IP6T_INV_DSTIP;
+ }
+
break;
case 'i':
/* In interface specification */
@@ -1989,11 +3394,21 @@ static int parse_rule_spec(struct connman_iptables *table,
if (len + 1 > IFNAMSIZ)
break;
- g_stpcpy(ctx->ip->iniface, optarg);
- memset(ctx->ip->iniface_mask, 0xff, len + 1);
+ if (ctx->type == AF_INET) {
+ g_stpcpy(ctx->ip->iniface, optarg);
+ memset(ctx->ip->iniface_mask, 0xff, len + 1);
+
+ if (invert)
+ ctx->ip->invflags |= IPT_INV_VIA_IN;
+ }
+
+ if (ctx->type == AF_INET6) {
+ g_stpcpy(ctx->ipv6->iniface, optarg);
+ memset(ctx->ipv6->iniface_mask, 0xff, len + 1);
- if (invert)
- ctx->ip->invflags |= IPT_INV_VIA_IN;
+ if (invert)
+ ctx->ipv6->invflags |= IP6T_INV_VIA_IN;
+ }
break;
case 'o':
@@ -2003,11 +3418,21 @@ static int parse_rule_spec(struct connman_iptables *table,
if (len + 1 > IFNAMSIZ)
break;
- g_stpcpy(ctx->ip->outiface, optarg);
- memset(ctx->ip->outiface_mask, 0xff, len + 1);
+ if (ctx->type == AF_INET) {
+ g_stpcpy(ctx->ip->outiface, optarg);
+ memset(ctx->ip->outiface_mask, 0xff, len + 1);
+
+ if (invert)
+ ctx->ip->invflags |= IPT_INV_VIA_OUT;
+ }
- if (invert)
- ctx->ip->invflags |= IPT_INV_VIA_OUT;
+ if (ctx->type == AF_INET6) {
+ g_stpcpy(ctx->ipv6->outiface, optarg);
+ memset(ctx->ipv6->outiface_mask, 0xff, len + 1);
+
+ if (invert)
+ ctx->ipv6->invflags |= IP6T_INV_VIA_OUT;
+ }
break;
case 'm':
@@ -2021,7 +3446,41 @@ static int parse_rule_spec(struct connman_iptables *table,
break;
case 'p':
+ enable_jmp();
+
+ if ((err = setjmp(env_state)) != 0) {
+ DBG("setjmp() called by longjmp() with value "
+ "%d", err);
+ disable_jmp();
+
+ /* Errors from parse_rule_spec are negative */
+ err = -EINVAL;
+ goto out;
+ }
+
ctx->proto = xtables_parse_protocol(optarg);
+
+ disable_jmp();
+
+ /*
+ * If protocol was set add it to ipt_ip.
+ * xtables_parse_protocol() returns 0 or
+ * UINT16_MAX (-1) on error
+ */
+ if (ctx->proto > 0 && ctx->proto < UINT16_MAX) {
+ if (ctx->type == AF_INET)
+ ctx->ip->proto = ctx->proto;
+
+ if (ctx->type == AF_INET6) {
+ ctx->ipv6->proto = ctx->proto;
+
+ /*
+ * Flags must be set for IPv6 if
+ * protocol is set.
+ */
+ ctx->ipv6->flags |= IP6T_F_PROTO;
+ }
+ }
break;
case 'j':
/* Target */
@@ -2051,6 +3510,8 @@ static int parse_rule_spec(struct connman_iptables *table,
err = parse_xt_modules(c, invert, ctx);
if (err == 1)
continue;
+ else if (err == -EINVAL)
+ goto out;
break;
}
@@ -2064,6 +3525,42 @@ out:
return err;
}
+static int current_type = -1;
+
+static int setup_xtables(int type)
+{
+ int err;
+
+ DBG("%d", type);
+
+ if (type == current_type)
+ return 0;
+
+ if (current_type != -1)
+ reset_xtables();
+
+ switch (type) {
+ case AF_INET:
+ err = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
+ break;
+ case AF_INET6:
+ err = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6);
+ break;
+ default:
+ return -1;
+ }
+
+ if (!err) {
+ current_type = type;
+ } else {
+ connman_error("error initializing xtables");
+ current_type = -1;
+ reset_xtables();
+ }
+
+ return err;
+}
+
static void reset_xtables(void)
{
struct xtables_match *xt_m;
@@ -2103,7 +3600,10 @@ static void cleanup_parse_context(struct parse_context *ctx)
GList *list;
g_strfreev(ctx->argv);
+
g_free(ctx->ip);
+ g_free(ctx->ipv6);
+
if (ctx->xt_t) {
g_free(ctx->xt_t->t);
ctx->xt_t->t = NULL;
@@ -2131,13 +3631,13 @@ static void cleanup_parse_context(struct parse_context *ctx)
g_free(ctx);
}
-int __connman_iptables_dump(const char *table_name)
+int __connman_iptables_dump(int type, const char *table_name)
{
struct connman_iptables *table;
- DBG("-t %s -L", table_name);
+ DBG("%d -t %s -L", type, table_name);
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table)
return -EINVAL;
@@ -2146,83 +3646,131 @@ int __connman_iptables_dump(const char *table_name)
return 0;
}
-int __connman_iptables_new_chain(const char *table_name,
+int __connman_iptables_new_chain(int type,
+ const char *table_name,
const char *chain)
{
struct connman_iptables *table;
- DBG("-t %s -N %s", table_name, chain);
+ DBG("%d -t %s -N %s", type, table_name, chain);
- table = get_table(table_name);
- if (!table)
+ table = get_table(type, table_name);
+ if (!table) {
return -EINVAL;
+ }
- return iptables_add_chain(table, chain);
+ switch (type) {
+ case AF_INET:
+ case AF_INET6:
+ return iptables_add_chain(table, chain);
+ }
+
+ return -EINVAL;
}
-int __connman_iptables_delete_chain(const char *table_name,
+int __connman_iptables_delete_chain(int type,
+ const char *table_name,
const char *chain)
{
struct connman_iptables *table;
- DBG("-t %s -X %s", table_name, chain);
+ DBG("%d -t %s -X %s", type, table_name, chain);
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table)
return -EINVAL;
return iptables_delete_chain(table, chain);
}
-int __connman_iptables_flush_chain(const char *table_name,
+int __connman_iptables_flush_chain(int type,
+ const char *table_name,
const char *chain)
{
struct connman_iptables *table;
- DBG("-t %s -F %s", table_name, chain);
+ DBG("%d -t %s -F %s", type, table_name, chain);
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table)
return -EINVAL;
return iptables_flush_chain(table, chain);
}
-int __connman_iptables_change_policy(const char *table_name,
+int __connman_iptables_find_chain(int type,
+ const char *table_name,
+ const char *chain)
+{
+ struct connman_iptables *table;
+
+ DBG("%d -t %s -F %s", type, table_name, chain);
+
+ table = get_table(type, table_name);
+ if (!table)
+ return -EINVAL;
+
+ if(!find_chain_head(table, chain))
+ return -ENOENT; // Not Found
+
+ return 0; // Found
+}
+
+int __connman_iptables_change_policy(int type,
+ const char *table_name,
const char *chain,
const char *policy)
{
struct connman_iptables *table;
- DBG("-t %s -F %s", table_name, chain);
+ DBG("%d -t %s -F %s", type, table_name, chain);
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table)
return -EINVAL;
return iptables_change_policy(table, chain, policy);
}
-int __connman_iptables_append(const char *table_name,
+static void iptables_ip_setup(struct iptables_ip *ip, struct parse_context *ctx)
+{
+ if (!ip || !ctx)
+ return;
+
+ ip->type = ctx->type;
+ ip->ip = ctx->ip;
+ ip->ip6 = ctx->ipv6;
+}
+
+int __connman_iptables_append(int type,
+ const char *table_name,
const char *chain,
const char *rule_spec)
{
struct connman_iptables *table;
struct parse_context *ctx;
+ struct iptables_ip ip = { 0 };
const char *target_name;
int err;
+ err = setup_xtables(type);
+
+ if (err < 0)
+ return err;
+
ctx = g_try_new0(struct parse_context, 1);
if (!ctx)
return -ENOMEM;
- DBG("-t %s -A %s %s", table_name, chain, rule_spec);
+ ctx->type = type;
+
+ DBG("%d -t %s -A %s %s", type, table_name, chain, rule_spec);
err = prepare_getopt_args(rule_spec, ctx);
if (err < 0)
goto out;
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table) {
err = -EINVAL;
goto out;
@@ -2237,8 +3785,10 @@ int __connman_iptables_append(const char *table_name,
else
target_name = ctx->xt_t->name;
- err = iptables_append_rule(table, ctx->ip, chain,
- target_name, ctx->xt_t, ctx->xt_rm);
+ iptables_ip_setup(&ip, ctx);
+
+ err = iptables_append_rule(table, &ip, chain, target_name, ctx->xt_t,
+ ctx->xt_rm);
out:
cleanup_parse_context(ctx);
reset_xtables();
@@ -2246,26 +3796,35 @@ out:
return err;
}
-int __connman_iptables_insert(const char *table_name,
+int __connman_iptables_insert(int type,
+ const char *table_name,
const char *chain,
const char *rule_spec)
{
struct connman_iptables *table;
struct parse_context *ctx;
+ struct iptables_ip ip = { 0 };
const char *target_name;
int err;
+ err = setup_xtables(type);
+
+ if (err < 0)
+ return err;
+
ctx = g_try_new0(struct parse_context, 1);
if (!ctx)
return -ENOMEM;
+
+ ctx->type = type;
- DBG("-t %s -I %s %s", table_name, chain, rule_spec);
+ DBG("%d -t %s -I %s %s", type, table_name, chain, rule_spec);
err = prepare_getopt_args(rule_spec, ctx);
if (err < 0)
goto out;
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table) {
err = -EINVAL;
goto out;
@@ -2280,8 +3839,10 @@ int __connman_iptables_insert(const char *table_name,
else
target_name = ctx->xt_t->name;
- err = iptables_insert_rule(table, ctx->ip, chain,
- target_name, ctx->xt_t, ctx->xt_rm);
+ iptables_ip_setup(&ip, ctx);
+
+ err = iptables_insert_rule(table, &ip, chain, target_name, ctx->xt_t,
+ ctx->xt_rm);
out:
cleanup_parse_context(ctx);
reset_xtables();
@@ -2289,26 +3850,35 @@ out:
return err;
}
-int __connman_iptables_delete(const char *table_name,
+int __connman_iptables_delete(int type,
+ const char *table_name,
const char *chain,
const char *rule_spec)
{
struct connman_iptables *table;
struct parse_context *ctx;
+ struct iptables_ip ip = { 0 };
const char *target_name;
int err;
+ err = setup_xtables(type);
+
+ if (err < 0)
+ return err;
+
ctx = g_try_new0(struct parse_context, 1);
if (!ctx)
return -ENOMEM;
+
+ ctx->type = type;
- DBG("-t %s -D %s %s", table_name, chain, rule_spec);
+ DBG("%d -t %s -D %s %s", type, table_name, chain, rule_spec);
err = prepare_getopt_args(rule_spec, ctx);
if (err < 0)
goto out;
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table) {
err = -EINVAL;
goto out;
@@ -2323,9 +3893,10 @@ int __connman_iptables_delete(const char *table_name,
else
target_name = ctx->xt_t->name;
- err = iptables_delete_rule(table, ctx->ip, chain,
- target_name, ctx->xt_t, ctx->xt_m,
- ctx->xt_rm);
+ iptables_ip_setup(&ip, ctx);
+
+ err = iptables_delete_rule(table, &ip, chain, target_name, ctx->xt_t,
+ ctx->xt_m, ctx->xt_rm);
out:
cleanup_parse_context(ctx);
reset_xtables();
@@ -2333,30 +3904,46 @@ out:
return err;
}
-int __connman_iptables_commit(const char *table_name)
+int __connman_iptables_commit(int type, const char *table_name)
{
struct connman_iptables *table;
- struct ipt_replace *repl;
+ struct iptables_replace repl = { 0 };
int err;
struct xt_counters_info *counters;
struct connman_iptables_entry *e;
GList *list;
unsigned int cnt;
- DBG("%s", table_name);
+ err = setup_xtables(type);
+
+ if (err < 0)
+ return err;
+
+ DBG("%d %s", type, table_name);
- table = g_hash_table_lookup(table_hash, table_name);
+ repl.type = type;
+
+ table = hash_table_lookup(type, table_name);
if (!table)
return -EINVAL;
- repl = iptables_blob(table);
- if(!repl)
- return -ENOMEM;
+ switch (type) {
+ case AF_INET:
+ repl.r = iptables_blob(table);
+ if (!repl.r)
+ return -ENOMEM;
+
+ break;
+ case AF_INET6:
+ repl.r6 = ip6tables_blob(table);
+ if (!repl.r6)
+ return -ENOMEM;
+ }
if (debug_enabled)
- dump_ipt_replace(repl);
+ dump_replace(&repl);
- err = iptables_replace(table, repl);
+ err = iptables_replace(table, &repl);
if (err < 0)
goto out_free;
@@ -2367,12 +3954,23 @@ int __connman_iptables_commit(const char *table_name)
err = -ENOMEM;
goto out_hash_remove;
}
- g_stpcpy(counters->name, table->info->name);
+ g_stpcpy(counters->name, iptables_table_get_info_name(table));
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];
+ if (e->counter_idx >= 0) {
+
+ switch (type) {
+ case AF_INET:
+ counters->counters[cnt] =
+ repl.r->counters[e->counter_idx];
+ break;
+ case AF_INET6:
+ counters->counters[cnt] =
+ repl.r6->counters[e->counter_idx];
+ break;
+ }
+ }
}
err = iptables_add_counters(table, counters);
g_free(counters);
@@ -2383,10 +3981,19 @@ int __connman_iptables_commit(const char *table_name)
err = 0;
out_hash_remove:
- g_hash_table_remove(table_hash, table_name);
+ hash_table_remove(type, table_name);
out_free:
- g_free(repl->counters);
- g_free(repl);
+ if (type == AF_INET && repl.r)
+ g_free(repl.r->counters);
+
+ if (type == AF_INET6 && repl.r6)
+ g_free(repl.r6->counters);
+
+ g_free(repl.r);
+ g_free(repl.r6);
+
+ reset_xtables();
+
return err;
}
@@ -2397,7 +4004,7 @@ static void remove_table(gpointer user_data)
table_cleanup(table);
}
-static int iterate_chains_cb(struct ipt_entry *entry, int builtin,
+static int iterate_chains_cb(struct connman_iptables_entry *entry, int builtin,
unsigned int hook, size_t size,
unsigned int offset, void *user_data)
{
@@ -2405,40 +4012,58 @@ static int iterate_chains_cb(struct ipt_entry *entry, int builtin,
connman_iptables_iterate_chains_cb_t cb = cbd->cb;
struct xt_entry_target *target;
- if (offset + entry->next_offset == size)
+ if (offset + iptables_entry_get_next_offset(entry) == size)
return 0;
- target = ipt_get_target(entry);
+ target = iptables_entry_get_target(entry);
- if (!g_strcmp0(target->u.user.name, IPT_ERROR_TARGET))
+ if (!g_strcmp0(target->u.user.name, get_error_target(entry->type))) {
(*cb)((const char *)target->data, cbd->user_data);
- else if (builtin >= 0)
+ } else if (builtin >= 0) {
(*cb)(hooknames[builtin], cbd->user_data);
+ }
return 0;
}
-int __connman_iptables_iterate_chains(const char *table_name,
+int __connman_iptables_iterate_chains(int type, const char *table_name,
connman_iptables_iterate_chains_cb_t cb,
void *user_data)
{
struct cb_data *cbd = cb_data_new(cb, user_data);
struct connman_iptables *table;
+ struct connman_iptables_entry entry = { 0 };
+ int err;
+
+ err = setup_xtables(type);
+
+ if (err < 0)
+ return err;
- table = get_table(table_name);
+ table = get_table(type, table_name);
if (!table) {
g_free(cbd);
return -EINVAL;
}
- iterate_entries(table->blob_entries->entrytable,
- table->info->valid_hooks,
- table->info->hook_entry,
- table->info->underflow,
- table->blob_entries->size,
+ entry.type = type;
+
+ if (type == AF_INET)
+ entry.entry = table->blob_entries->entrytable;
+
+ if (type == AF_INET6)
+ entry.entry6 = table->blob_entries6->entrytable;
+
+ iterate_entries(&entry,
+ iptables_table_get_info_valid_hooks(table),
+ iptables_table_get_info_hook_entry(table),
+ iptables_table_get_info_underflow(table),
+ iptables_table_get_entries_size(table),
iterate_chains_cb, cbd);
g_free(cbd);
+
+ reset_xtables();
return 0;
}
@@ -2453,7 +4078,8 @@ int __connman_iptables_init(void)
table_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_table);
- xtables_init_all(&iptables_globals, NFPROTO_IPV4);
+ table_hash_ipv6 = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, remove_table);
return 0;
}
@@ -2463,4 +4089,6 @@ void __connman_iptables_cleanup(void)
DBG("");
g_hash_table_destroy(table_hash);
+ g_hash_table_destroy(table_hash_ipv6);
}
+
diff --git a/src/ipv6pd.c b/src/ipv6pd.c
index 0d221f07..8cd2a33e 100755
--- a/src/ipv6pd.c
+++ b/src/ipv6pd.c
@@ -41,7 +41,6 @@ static guint timer_uplink;
static guint timer_ra;
static char *default_interface;
static GSList *prefixes;
-static GHashTable *timer_hash;
static void *rs_context;
static int setup_prefix_delegation(struct connman_service *service);
@@ -139,7 +138,7 @@ static gboolean do_setup(gpointer data)
if (!default_interface)
DBG("No uplink connection, retrying prefix delegation");
- ret = setup_prefix_delegation(__connman_service_get_default());
+ ret = setup_prefix_delegation(connman_service_get_default());
if (ret < 0 && ret != -EINPROGRESS)
return TRUE; /* delegation error, try again */
@@ -155,7 +154,7 @@ static void dhcpv6_renew_callback(struct connman_network *network,
if (status == CONNMAN_DHCPV6_STATUS_SUCCEED)
dhcpv6_callback(network, status, data);
else
- setup_prefix_delegation(__connman_service_get_default());
+ setup_prefix_delegation(connman_service_get_default());
}
static void cleanup(void)
@@ -165,11 +164,6 @@ static void cleanup(void)
timer_uplink = 0;
}
- if (timer_hash) {
- g_hash_table_destroy(timer_hash);
- timer_hash = NULL;
- }
-
if (prefixes) {
g_slist_free_full(prefixes, g_free);
prefixes = NULL;
@@ -260,13 +254,6 @@ static int setup_prefix_delegation(struct connman_service *service)
return err;
}
-static void cleanup_timer(gpointer user_data)
-{
- guint timer = GPOINTER_TO_UINT(user_data);
-
- g_source_remove(timer);
-}
-
static void update_default_interface(struct connman_service *service)
{
setup_prefix_delegation(service);
@@ -275,7 +262,7 @@ static void update_default_interface(struct connman_service *service)
static void update_ipconfig(struct connman_service *service,
struct connman_ipconfig *ipconfig)
{
- if (!service || service != __connman_service_get_default())
+ if (!service || service != connman_service_get_default())
return;
if (ipconfig != __connman_service_get_ip6config(service))
@@ -308,7 +295,7 @@ static void update_ipconfig(struct connman_service *service,
}
}
-static struct connman_notifier pd_notifier = {
+static const struct connman_notifier pd_notifier = {
.name = "IPv6 prefix delegation",
.default_changed = update_default_interface,
.ipconfig_changed = update_ipconfig,
@@ -333,16 +320,13 @@ int __connman_ipv6pd_setup(const char *bridge)
bridge_index = connman_inet_ifindex(bridge);
- timer_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, cleanup_timer);
-
err = __connman_inet_ipv6_start_recv_rs(bridge_index, rs_received,
NULL, &rs_context);
if (err < 0)
DBG("Cannot receive router solicitation %d/%s",
err, strerror(-err));
- service = __connman_service_get_default();
+ service = connman_service_get_default();
if (service) {
/*
* We have an uplink connection already, try to use it.
diff --git a/src/log.c b/src/log.c
index 3112a43f..444e75f6 100755
--- a/src/log.c
+++ b/src/log.c
@@ -23,15 +23,14 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
-#include <execinfo.h>
#include <dlfcn.h>
+#include <signal.h>
#include "connman.h"
@@ -175,6 +174,9 @@ void __connman_log_s(int log_priority, const char *format, ...)
}
#endif
+/* This makes sure we always have a __debug section. */
+CONNMAN_DEBUG_DEFINE(dummy);
+
/**
* connman_info:
* @format: format string
@@ -227,7 +229,6 @@ void connman_error(const char *format, ...)
vsyslog(LOG_ERR, format, ap);
va_end(ap);
- fflush(log_file);
}
/**
@@ -246,122 +247,13 @@ void connman_debug(const char *format, ...)
vsyslog(LOG_DEBUG, format, ap);
va_end(ap);
- fflush(log_file);
-}
-
-static void print_backtrace(unsigned int offset)
-{
- void *frames[99];
- size_t n_ptrs;
- unsigned int i;
- int outfd[2], infd[2];
- int pathlen;
- pid_t pid;
-
- if (!program_exec)
- return;
-
- pathlen = strlen(program_path);
-
- n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
- if (n_ptrs < offset)
- return;
-
- if (pipe(outfd) < 0)
- return;
-
- if (pipe(infd) < 0) {
- close(outfd[0]);
- close(outfd[1]);
- return;
- }
-
- pid = fork();
- if (pid < 0) {
- close(outfd[0]);
- close(outfd[1]);
- close(infd[0]);
- close(infd[1]);
- return;
- }
-
- if (pid == 0) {
- close(outfd[1]);
- close(infd[0]);
-
- dup2(outfd[0], STDIN_FILENO);
- dup2(infd[1], STDOUT_FILENO);
-
- execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
-
- exit(EXIT_FAILURE);
- }
-
- close(outfd[0]);
- close(infd[1]);
-
- connman_error("++++++++ backtrace ++++++++");
-
- for (i = offset; i < n_ptrs - 1; i++) {
- Dl_info info;
- char addr[20], buf[PATH_MAX * 2];
- int len, written;
- char *ptr, *pos;
-
- dladdr(frames[i], &info);
-
- len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
- if (len < 0)
- break;
-
- written = write(outfd[1], addr, len);
- if (written < 0)
- break;
-
- len = read(infd[0], buf, sizeof(buf) - 1);
- if (len < 0)
- break;
-
- buf[len] = '\0';
-
- pos = strchr(buf, '\n');
-#if defined TIZEN_EXT
- if (pos) {
-#endif
- *pos++ = '\0';
-
- if (strcmp(buf, "??") == 0) {
- connman_error("#%-2u %p in %s", i - offset,
- frames[i], info.dli_fname);
- continue;
- }
-
- ptr = strchr(pos, '\n');
- *ptr++ = '\0';
-
- if (strncmp(pos, program_path, pathlen) == 0)
- pos += pathlen + 1;
-
- connman_error("#%-2u %p in %s() at %s", i - offset,
- frames[i], buf, pos);
-#if defined TIZEN_EXT
- }
-#endif
- }
-
- connman_error("+++++++++++++++++++++++++++");
-
- kill(pid, SIGTERM);
-
- close(outfd[1]);
- close(infd[0]);
}
static void signal_handler(int signo)
{
connman_error("Aborting (signal %d) [%s]", signo, program_exec);
- print_backtrace(2);
+ print_backtrace(program_path, program_exec, 2);
exit(EXIT_FAILURE);
}
diff --git a/src/main.c b/src/main.c
index 37752870..8221c35a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -30,17 +30,19 @@
#include <string.h>
#include <signal.h>
#include <sys/signalfd.h>
-#include <sys/types.h>
-#include <sys/resource.h>
#include <getopt.h>
#include <sys/stat.h>
#include <net/if.h>
#include <netdb.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <gdbus.h>
#include "connman.h"
+#define CONF_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]) - 1)
+
#define DEFAULT_INPUT_REQUEST_TIMEOUT (120 * 1000)
#define DEFAULT_BROWSER_LAUNCH_TIMEOUT (300 * 1000)
@@ -54,6 +56,11 @@ static char *default_auto_connect[] = {
NULL
};
+static char *default_favorite_techs[] = {
+ "ethernet",
+ NULL
+};
+
static char *default_blacklist[] = {
"vmnet",
"vboxnet",
@@ -68,6 +75,7 @@ static struct {
bool bg_scan;
char **pref_timeservers;
unsigned int *auto_connect;
+ unsigned int *favorite_techs;
unsigned int *preferred_techs;
unsigned int *always_connected_techs;
char **fallback_nameservers;
@@ -75,21 +83,25 @@ static struct {
unsigned int timeout_browserlaunch;
char **blacklisted_interfaces;
bool allow_hostname_updates;
+ bool allow_domainname_updates;
bool single_tech;
char **tethering_technologies;
bool persistent_tethering_mode;
bool enable_6to4;
char *vendor_class_id;
bool enable_online_check;
+ bool auto_connect_roaming_services;
+ bool acd;
+ bool use_gateways_as_timeservers;
#if defined TIZEN_EXT
char **cellular_interfaces;
bool tizen_tv_extension;
- bool use_gateway_timeserver;
#endif
} connman_settings = {
.bg_scan = true,
.pref_timeservers = NULL,
.auto_connect = NULL,
+ .favorite_techs = NULL,
.preferred_techs = NULL,
.always_connected_techs = NULL,
.fallback_nameservers = NULL,
@@ -97,22 +109,26 @@ static struct {
.timeout_browserlaunch = DEFAULT_BROWSER_LAUNCH_TIMEOUT,
.blacklisted_interfaces = NULL,
.allow_hostname_updates = true,
+ .allow_domainname_updates = true,
.single_tech = false,
.tethering_technologies = NULL,
.persistent_tethering_mode = false,
.enable_6to4 = false,
.vendor_class_id = NULL,
.enable_online_check = true,
+ .auto_connect_roaming_services = false,
+ .acd = false,
+ .use_gateways_as_timeservers = false,
#if defined TIZEN_EXT
.cellular_interfaces = NULL,
.tizen_tv_extension = false,
- .use_gateway_timeserver = false,
#endif
};
#define CONF_BG_SCAN "BackgroundScanning"
#define CONF_PREF_TIMESERVERS "FallbackTimeservers"
-#define CONF_AUTO_CONNECT "DefaultAutoConnectTechnologies"
+#define CONF_AUTO_CONNECT_TECHS "DefaultAutoConnectTechnologies"
+#define CONF_FAVORITE_TECHS "DefaultFavoriteTechnologies"
#define CONF_ALWAYS_CONNECTED_TECHS "AlwaysConnectedTechnologies"
#define CONF_PREFERRED_TECHS "PreferredTechnologies"
#define CONF_FALLBACK_NAMESERVERS "FallbackNameservers"
@@ -120,22 +136,25 @@ static struct {
#define CONF_TIMEOUT_BROWSERLAUNCH "BrowserLaunchTimeout"
#define CONF_BLACKLISTED_INTERFACES "NetworkInterfaceBlacklist"
#define CONF_ALLOW_HOSTNAME_UPDATES "AllowHostnameUpdates"
+#define CONF_ALLOW_DOMAINNAME_UPDATES "AllowDomainnameUpdates"
#define CONF_SINGLE_TECH "SingleConnectedTechnology"
#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"
+#define CONF_AUTO_CONNECT_ROAMING_SERVICES "AutoConnectRoamingServices"
+#define CONF_ACD "AddressConflictDetection"
+#define CONF_USE_GATEWAYS_AS_TIMESERVERS "UseGatewaysAsTimeservers"
#if defined TIZEN_EXT
#define CONF_CELLULAR_INTERFACE "NetworkCellularInterfaceList"
#define CONF_TIZEN_TV_EXT "TizenTVExtension"
-#define CONF_USE_GATEWAY_TIMESERVER "UseGatewayTimeserver"
#endif
static const char *supported_options[] = {
CONF_BG_SCAN,
CONF_PREF_TIMESERVERS,
- CONF_AUTO_CONNECT,
+ CONF_AUTO_CONNECT_TECHS,
CONF_ALWAYS_CONNECTED_TECHS,
CONF_PREFERRED_TECHS,
CONF_FALLBACK_NAMESERVERS,
@@ -143,15 +162,19 @@ static const char *supported_options[] = {
CONF_TIMEOUT_BROWSERLAUNCH,
CONF_BLACKLISTED_INTERFACES,
CONF_ALLOW_HOSTNAME_UPDATES,
+ CONF_ALLOW_DOMAINNAME_UPDATES,
CONF_SINGLE_TECH,
CONF_TETHERING_TECHNOLOGIES,
CONF_PERSISTENT_TETHERING_MODE,
CONF_ENABLE_6TO4,
+ CONF_VENDOR_CLASS_ID,
CONF_ENABLE_ONLINE_CHECK,
+ CONF_AUTO_CONNECT_ROAMING_SERVICES,
+ CONF_ACD,
+ CONF_USE_GATEWAYS_AS_TIMESERVERS,
#if defined TIZEN_EXT
CONF_CELLULAR_INTERFACE,
CONF_TIZEN_TV_EXT,
- CONF_USE_GATEWAY_TIMESERVER,
#endif
NULL
};
@@ -289,13 +312,6 @@ static void check_Tizen_configuration(GKeyFile *config)
connman_settings.tizen_tv_extension = boolean;
g_clear_error(&error);
-
- boolean = __connman_config_get_bool(config, "General",
- CONF_USE_GATEWAY_TIMESERVER, &error);
- if (!error)
- connman_settings.use_gateway_timeserver = boolean;
-
- g_clear_error(&error);
}
static void set_nofile_inc(void)
@@ -328,7 +344,9 @@ static void parse_config(GKeyFile *config)
if (!config) {
connman_settings.auto_connect =
- parse_service_types(default_auto_connect, 3);
+ parse_service_types(default_auto_connect, CONF_ARRAY_SIZE(default_auto_connect));
+ connman_settings.favorite_techs =
+ parse_service_types(default_favorite_techs, CONF_ARRAY_SIZE(default_favorite_techs));
connman_settings.blacklisted_interfaces =
g_strdupv(default_blacklist);
return;
@@ -351,14 +369,26 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
str_list = __connman_config_get_string_list(config, "General",
- CONF_AUTO_CONNECT, &len, &error);
+ CONF_AUTO_CONNECT_TECHS, &len, &error);
if (!error)
connman_settings.auto_connect =
parse_service_types(str_list, len);
else
connman_settings.auto_connect =
- parse_service_types(default_auto_connect, 3);
+ parse_service_types(default_auto_connect, CONF_ARRAY_SIZE(default_auto_connect));
+
+ g_clear_error(&error);
+
+ str_list = __connman_config_get_string_list(config, "General",
+ CONF_FAVORITE_TECHS, &len, &error);
+
+ if (!error)
+ connman_settings.favorite_techs =
+ parse_service_types(str_list, len);
+ else
+ connman_settings.favorite_techs =
+ parse_service_types(default_favorite_techs, CONF_ARRAY_SIZE(default_favorite_techs));
g_strfreev(str_list);
@@ -431,6 +461,14 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
boolean = __connman_config_get_bool(config, "General",
+ CONF_ALLOW_DOMAINNAME_UPDATES,
+ &error);
+ if (!error)
+ connman_settings.allow_domainname_updates = boolean;
+
+ g_clear_error(&error);
+
+ boolean = __connman_config_get_bool(config, "General",
CONF_SINGLE_TECH, &error);
if (!error)
connman_settings.single_tech = boolean;
@@ -477,6 +515,26 @@ static void parse_config(GKeyFile *config)
g_clear_error(&error);
+ boolean = __connman_config_get_bool(config, "General",
+ CONF_AUTO_CONNECT_ROAMING_SERVICES, &error);
+ if (!error)
+ connman_settings.auto_connect_roaming_services = boolean;
+
+ g_clear_error(&error);
+
+ boolean = __connman_config_get_bool(config, "General", CONF_ACD, &error);
+ if (!error)
+ connman_settings.acd = boolean;
+
+ g_clear_error(&error);
+
+ boolean = __connman_config_get_bool(config, "General",
+ CONF_USE_GATEWAYS_AS_TIMESERVERS, &error);
+ if (!error)
+ connman_settings.use_gateways_as_timeservers = boolean;
+
+ g_clear_error(&error);
+
#if defined TIZEN_EXT
check_Tizen_configuration(config);
#endif
@@ -632,9 +690,9 @@ static GOptionEntry options[] = {
G_OPTION_ARG_CALLBACK, parse_debug,
"Specify debug options to enable", "DEBUG" },
{ "device", 'i', 0, G_OPTION_ARG_STRING, &option_device,
- "Specify networking device or interface", "DEV" },
+ "Specify networking devices or interfaces", "DEV,..." },
{ "nodevice", 'I', 0, G_OPTION_ARG_STRING, &option_nodevice,
- "Specify networking interface to ignore", "DEV" },
+ "Specify networking interfaces to ignore", "DEV,..." },
{ "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
"Specify plugins to load", "NAME,..." },
{ "noplugin", 'P', 0, G_OPTION_ARG_CALLBACK, &parse_noplugin,
@@ -646,7 +704,7 @@ static GOptionEntry options[] = {
"Don't fork daemon to background" },
{ "nodnsproxy", 'r', G_OPTION_FLAG_REVERSE,
G_OPTION_ARG_NONE, &option_dnsproxy,
- "Don't enable DNS Proxy" },
+ "Don't support DNS resolving" },
{ "nobacktrace", 0, G_OPTION_FLAG_REVERSE,
G_OPTION_ARG_NONE, &option_backtrace,
"Don't print out backtrace information" },
@@ -678,6 +736,9 @@ bool connman_setting_get_bool(const char *key)
if (g_str_equal(key, CONF_ALLOW_HOSTNAME_UPDATES))
return connman_settings.allow_hostname_updates;
+ if (g_str_equal(key, CONF_ALLOW_DOMAINNAME_UPDATES))
+ return connman_settings.allow_domainname_updates;
+
if (g_str_equal(key, CONF_SINGLE_TECH))
return connman_settings.single_tech;
@@ -690,10 +751,14 @@ bool connman_setting_get_bool(const char *key)
if (g_str_equal(key, CONF_ENABLE_ONLINE_CHECK))
return connman_settings.enable_online_check;
-#if defined TIZEN_EXT
- if (g_str_equal(key, CONF_USE_GATEWAY_TIMESERVER))
- return connman_settings.use_gateway_timeserver;
-#endif
+ if (g_str_equal(key, CONF_AUTO_CONNECT_ROAMING_SERVICES))
+ return connman_settings.auto_connect_roaming_services;
+
+ if (g_str_equal(key, CONF_ACD))
+ return connman_settings.acd;
+
+ if (g_str_equal(key, CONF_USE_GATEWAYS_AS_TIMESERVERS))
+ return connman_settings.use_gateways_as_timeservers;
return false;
}
@@ -722,9 +787,12 @@ char **connman_setting_get_string_list(const char *key)
unsigned int *connman_setting_get_uint_list(const char *key)
{
- if (g_str_equal(key, CONF_AUTO_CONNECT))
+ if (g_str_equal(key, CONF_AUTO_CONNECT_TECHS))
return connman_settings.auto_connect;
+ if (g_str_equal(key, CONF_FAVORITE_TECHS))
+ return connman_settings.favorite_techs;
+
if (g_str_equal(key, CONF_PREFERRED_TECHS))
return connman_settings.preferred_techs;
@@ -926,6 +994,7 @@ int main(int argc, char *argv[])
g_strfreev(connman_settings.pref_timeservers);
g_free(connman_settings.auto_connect);
+ g_free(connman_settings.favorite_techs);
g_free(connman_settings.preferred_techs);
g_strfreev(connman_settings.fallback_nameservers);
g_strfreev(connman_settings.blacklisted_interfaces);
diff --git a/src/main.conf b/src/main.conf
index 80724d52..c3190ca3 100755
--- a/src/main.conf
+++ b/src/main.conf
@@ -14,18 +14,27 @@
# user interface designs.
# BrowserLaunchTimeout = 300
-# Enable background scanning. Default is true.
-# Background scanning will start every 5 minutes unless
-# the scan list is empty. In that case, a simple backoff
-# mechanism starting from 10s up to 5 minutes will run.
+# If wifi is disconnected, the background scanning will follow a simple
+# backoff mechanism from 3s up to 5 minutes. Then, it will stay in 5
+# minutes unless user specifically asks for scanning through a D-Bus
+# call. If so, the mechanism will start again from 3s. This feature
+# activates also the background scanning while being connected, which
+# is required for roaming on wifi.
+# When BackgroundScanning is false, ConnMan will not perform any scan
+# regardless of wifi is connected or not, unless it is requested by
+# the user through a D-Bus call.
# BackgroundScanning = true
BackgroundScanning = false
+# Assume that service gateways also function as timeservers.
+# UseGatewaysAsTimeservers = false
+
# List of Fallback timeservers separated by ",".
# These timeservers are used for NTP sync when there are
-# no timeserver set by the user or by the service.
-# These can contain mixed combination of fully qualified
-# domain names, IPv4 and IPv6 addresses.
+# no timeservers set by the user or by the service, and
+# when UseGatewaysAsTimeservers = false. These can contain
+# mixed combination of fully qualified domain names, IPv4
+# and IPv6 addresses.
# FallbackTimeservers =
#FallbackTimeservers = pool.ntp.org
@@ -58,17 +67,22 @@ PreferredTechnologies = wifi, ethernet
# List of blacklisted network interfaces separated by ",".
# Found interfaces will be compared to the list and will
-# not be handled by connman, if their first characters
+# not be handled by ConnMan, if their first characters
# match any of the list entries. Default value is
# 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
+NetworkInterfaceBlacklist = veth,vmnet,vboxnet,virbr,usb,rndis,rmnet,rev_rmnet,dummy,seth_td,seth_w
-# Allow connman to change the system hostname. This can
+# Allow ConnMan to change the system hostname. This can
# happen for example if we receive DHCP hostname option.
# Default value is true.
# AllowHostnameUpdates = true
+# Allow ConnMan to change the system domainname. This can
+# happen for example if we receive DHCP domainname option.
+# Default value is true.
+# AllowDomainnameUpdates = true
+
# Keep only a single connected technology at any time. When a new
# service is connected by the user or a better one is found according
# to PreferredTechnologies, the new service is kept connected and all
@@ -123,8 +137,20 @@ SingleConnectedTechnology = true
# This setting has no effect if SingleConnectedTechnologies is enabled.
# AlwaysConnectedTechnologies =
-NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w
-
# Allow connman to add service gateway to the time server list.
# Default value is false.
-# UseGatewayTimeserver = false
+# UseGatewaysAsTimeservers = false
+
+# Enable auto connection of services in roaming.
+# If this setting is false, roaming services are not auto-connected by ConnMan.
+# Default value is false.
+# AutoConnectRoamingServices = false
+
+# Enable address conflict detection
+# If this setting is true, ConnMan will send probe ARP packets to see
+# if an IPv4 address is already in use before assigning the address
+# to an interface (in accordance with RFC 5227).
+# Default value is false.
+# AddressConflictDetection = false
+
+NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w
diff --git a/src/main_disable_eth.conf b/src/main_disable_eth.conf
index ea4a9ddb..4cc22f1d 100755
--- a/src/main_disable_eth.conf
+++ b/src/main_disable_eth.conf
@@ -111,4 +111,4 @@ NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w
# Allow connman to add service gateway to the time server list.
# Default value is false.
-# UseGatewayTimeserver = false
+# UseGatewaysAsTimeservers = false
diff --git a/src/main_ivi.conf b/src/main_ivi.conf
index c7e65c48..8ac0d589 100755
--- a/src/main_ivi.conf
+++ b/src/main_ivi.conf
@@ -111,4 +111,4 @@ NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w
# Allow connman to add service gateway to the time server list.
# Default value is false.
-# UseGatewayTimeserver = false
+# UseGatewaysAsTimeservers = false
diff --git a/src/main_tv.conf b/src/main_tv.conf
index 44d1b025..7a72dbe1 100755
--- a/src/main_tv.conf
+++ b/src/main_tv.conf
@@ -111,7 +111,7 @@ NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w
# Allow connman to add service gateway to the time server list.
# Default value is false.
-# UseGatewayTimeserver = false
+# UseGatewaysAsTimeservers = false
# Enable Tizen TV Profile Features
TizenTVExtension = true
diff --git a/src/manager.c b/src/manager.c
index bd44fea4..583b2ad1 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -111,20 +111,6 @@ static DBusMessage *set_property(DBusConnection *conn,
dbus_message_iter_get_basic(&value, &offlinemode);
- if (offlinemode) {
- uid_t uid;
- if (connman_dbus_get_connection_unix_user_sync(conn,
- dbus_message_get_sender(msg),
- &uid) < 0) {
- DBG("Can not get unix user id!");
- return __connman_error_permission_denied(msg);
- }
-
- if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
- DBG("Not allow this user to turn on offlinemode now!");
- return __connman_error_permission_denied(msg);
- }
- }
__connman_technology_set_offlinemode(offlinemode);
} else if (g_str_equal(name, "SessionMode")) {
@@ -132,9 +118,8 @@ static DBusMessage *set_property(DBusConnection *conn,
return __connman_error_invalid_arguments(msg);
dbus_message_iter_get_basic(&value, &sessionmode);
- }
#if defined TIZEN_EXT
- else if (g_str_equal(name, "AutoConnectMode") == TRUE) {
+ } else if (g_str_equal(name, "AutoConnectMode") == TRUE) {
bool automode;
if (type != DBUS_TYPE_BOOLEAN)
@@ -143,9 +128,8 @@ static DBusMessage *set_property(DBusConnection *conn,
dbus_message_iter_get_basic(&value, &automode);
__connman_service_set_auto_connect_mode(automode);
- }
#endif
- else
+ } else
return __connman_error_invalid_property(msg);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
@@ -206,7 +190,7 @@ static void idle_state(bool idle)
return;
}
-static struct connman_notifier technology_notifier = {
+static const struct connman_notifier technology_notifier = {
.name = "manager",
.priority = CONNMAN_NOTIFIER_PRIORITY_HIGH,
.idle_state = idle_state,
@@ -251,6 +235,27 @@ static DBusMessage *get_peers(DBusConnection *conn,
return reply;
}
+static DBusMessage *get_tethering_clients(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+
+ __connman_tethering_list_clients(&array);
+
+ dbus_message_iter_close_container(&iter, &array);
+ return reply;
+}
+
static DBusMessage *connect_provider(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -664,6 +669,9 @@ static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("GetPeers",
NULL, GDBUS_ARGS({ "peers", "a(oa{sv})" }),
get_peers) },
+ { GDBUS_METHOD("GetTetheringClients",
+ NULL, GDBUS_ARGS({ "tethering_clients", "as" }),
+ get_tethering_clients) },
{ GDBUS_DEPRECATED_ASYNC_METHOD("ConnectProvider",
GDBUS_ARGS({ "provider", "a{sv}" }),
GDBUS_ARGS({ "path", "o" }),
diff --git a/src/nat.c b/src/nat.c
index fb557101..681acb21 100755
--- a/src/nat.c
+++ b/src/nat.c
@@ -55,8 +55,10 @@ static int enable_ip_forward(bool enable)
if (read(f, &value, sizeof(value)) < 0)
value = 0;
- if (lseek(f, 0, SEEK_SET) < 0)
+ if (lseek(f, 0, SEEK_SET) < 0) {
+ close(f);
return -errno;
+ }
}
if (enable) {
@@ -201,7 +203,7 @@ static void cleanup_nat(gpointer data)
g_free(nat);
}
-static struct connman_notifier nat_notifier = {
+static const struct connman_notifier nat_notifier = {
.name = "nat",
.default_changed = update_default_interface,
};
diff --git a/src/network.c b/src/network.c
index fc57dcc8..a6d635ec 100755
--- a/src/network.c
+++ b/src/network.c
@@ -27,6 +27,8 @@
#include <string.h>
#include "connman.h"
+#include <connman/acd.h>
+#include "src/shared/arp.h"
/*
* How many times to send RS with the purpose of
@@ -48,6 +50,8 @@
*/
#define RTR_SOLICITATION_INTERVAL 4
+#define DHCP_RETRY_TIMEOUT 10
+
static GSList *network_list = NULL;
static GSList *driver_list = NULL;
@@ -67,6 +71,9 @@ struct connman_network {
int index;
int router_solicit_count;
int router_solicit_refresh_count;
+ struct acd_host *acd_host;
+ guint ipv4ll_timeout;
+ guint dhcp_timeout;
struct connman_network_driver *driver;
void *driver_data;
@@ -97,6 +104,7 @@ struct connman_network {
char *private_key_passphrase;
char *phase2_auth;
bool wps;
+ bool wps_advertizing;
bool use_wps;
char *pin_wps;
#if defined TIZEN_EXT
@@ -179,6 +187,264 @@ static void set_configuration(struct connman_network *network,
type);
}
+void connman_network_append_acddbus(DBusMessageIter *dict,
+ struct connman_network *network)
+{
+ if (!network->acd_host)
+ return;
+
+ acd_host_append_dbus_property(network->acd_host, dict);
+}
+
+static int start_acd(struct connman_network *network);
+
+static void remove_ipv4ll_timeout(struct connman_network *network)
+{
+ if (network->ipv4ll_timeout > 0) {
+ g_source_remove(network->ipv4ll_timeout);
+ network->ipv4ll_timeout = 0;
+ }
+}
+
+static void acd_host_ipv4_available(struct acd_host *acd, gpointer user_data)
+{
+ struct connman_network *network = user_data;
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
+ int err;
+
+ if (!network)
+ return;
+
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return;
+
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
+ if (!ipconfig_ipv4) {
+ connman_error("Service has no IPv4 configuration");
+ return;
+ }
+
+ err = __connman_ipconfig_address_add(ipconfig_ipv4);
+ if (err < 0)
+ goto err;
+
+#if defined TIZEN_EXT
+ err = __connman_ipconfig_gateway_add(ipconfig_ipv4, service);
+#else
+ err = __connman_ipconfig_gateway_add(ipconfig_ipv4);
+#endif
+ if (err < 0)
+ goto err;
+
+ __connman_service_save(service);
+
+ return;
+
+err:
+ connman_network_set_error(__connman_service_get_network(service),
+ CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
+}
+
+static int start_ipv4ll(struct connman_network *network)
+{
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
+ struct in_addr addr;
+ char *address;
+
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return -EINVAL;
+
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
+ if (!ipconfig_ipv4) {
+ connman_error("Service has no IPv4 configuration");
+ return -EINVAL;
+ }
+
+ /* Apply random IPv4 address. */
+ addr.s_addr = htonl(arp_random_ip());
+ address = inet_ntoa(addr);
+ if (!address) {
+ connman_error("Could not convert IPv4LL random address %u",
+ addr.s_addr);
+ return -EINVAL;
+ }
+ __connman_ipconfig_set_local(ipconfig_ipv4, address);
+
+ connman_info("Probing IPv4LL address %s", address);
+ return start_acd(network);
+}
+
+static gboolean start_ipv4ll_ontimeout(gpointer data)
+{
+ struct connman_network *network = data;
+
+ if (!network)
+ return FALSE;
+
+ /* Start IPv4LL ACD. */
+ start_ipv4ll(network);
+
+ return FALSE;
+}
+
+static void acd_host_ipv4_lost(struct acd_host *acd, gpointer user_data)
+{
+ struct connman_network *network = user_data;
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
+ enum connman_ipconfig_type type;
+ enum connman_ipconfig_method method;
+
+ if (!network)
+ return;
+
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return;
+
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
+ if (!ipconfig_ipv4) {
+ connman_error("Service has no IPv4 configuration");
+ return;
+ }
+
+ type = __connman_ipconfig_get_config_type(ipconfig_ipv4);
+ if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
+ return;
+
+ __connman_ipconfig_address_remove(ipconfig_ipv4);
+
+ method = __connman_ipconfig_get_method(ipconfig_ipv4);
+ if (method == CONNMAN_IPCONFIG_METHOD_DHCP) {
+ /*
+ * We have one more chance for DHCP. If this fails
+ * acd_host_ipv4_conflict will be called.
+ */
+ network = __connman_service_get_network(service);
+ if (network)
+ __connman_network_enable_ipconfig(network, ipconfig_ipv4);
+ } else {
+ /* Start IPv4LL ACD. */
+ start_ipv4ll(network);
+ }
+}
+
+static void acd_host_ipv4_conflict(struct acd_host *acd, gpointer user_data)
+{
+ struct connman_network *network = user_data;
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
+ enum connman_ipconfig_method method;
+
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return;
+
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
+ if (!ipconfig_ipv4) {
+ connman_error("Service has no IPv4 configuration");
+ return;
+ }
+
+ method = __connman_ipconfig_get_method(ipconfig_ipv4);
+ connman_info("%s conflict counts=%u", __FUNCTION__,
+ acd_host_get_conflicts_count(acd));
+
+ if (method == CONNMAN_IPCONFIG_METHOD_DHCP &&
+ acd_host_get_conflicts_count(acd) < 2) {
+ connman_info("%s Sending DHCP decline", __FUNCTION__);
+ __connman_dhcp_decline(ipconfig_ipv4);
+
+ connman_network_set_connected_dhcp_later(network, DHCP_RETRY_TIMEOUT);
+ __connman_ipconfig_set_local(ipconfig_ipv4, NULL);
+ } else {
+ if (method == CONNMAN_IPCONFIG_METHOD_DHCP) {
+ __connman_ipconfig_set_method(ipconfig_ipv4,
+ CONNMAN_IPCONFIG_METHOD_AUTO);
+ __connman_dhcp_decline(ipconfig_ipv4);
+ }
+ /* Start IPv4LL ACD. */
+ start_ipv4ll(network);
+ }
+}
+
+static void acd_host_ipv4_maxconflict(struct acd_host *acd, gpointer user_data)
+{
+ struct connman_network *network = user_data;
+
+ remove_ipv4ll_timeout(network);
+ connman_info("Had maximum number of conflicts. Next IPv4LL address will be "
+ "tried in %d seconds", RATE_LIMIT_INTERVAL);
+ /* Wait, then start IPv4LL ACD. */
+ network->ipv4ll_timeout =
+ g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+ RATE_LIMIT_INTERVAL,
+ start_ipv4ll_ontimeout,
+ network,
+ NULL);
+}
+
+static int start_acd(struct connman_network *network)
+{
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
+ const char* address;
+ struct in_addr addr;
+
+ remove_ipv4ll_timeout(network);
+
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return -EINVAL;
+
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
+ if (!ipconfig_ipv4) {
+ connman_error("Service has no IPv4 configuration");
+ return -EINVAL;
+ }
+
+ if (!network->acd_host) {
+ int index;
+
+ index = __connman_ipconfig_get_index(ipconfig_ipv4);
+ network->acd_host = acd_host_new(index,
+ connman_service_get_dbuspath(service));
+ if (!network->acd_host) {
+ connman_error("Could not create ACD data structure");
+ return -EINVAL;
+ }
+
+ acd_host_register_event(network->acd_host,
+ ACD_HOST_EVENT_IPV4_AVAILABLE,
+ acd_host_ipv4_available, network);
+ acd_host_register_event(network->acd_host,
+ ACD_HOST_EVENT_IPV4_LOST,
+ acd_host_ipv4_lost, network);
+ acd_host_register_event(network->acd_host,
+ ACD_HOST_EVENT_IPV4_CONFLICT,
+ acd_host_ipv4_conflict, network);
+ acd_host_register_event(network->acd_host,
+ ACD_HOST_EVENT_IPV4_MAXCONFLICT,
+ acd_host_ipv4_maxconflict, network);
+ }
+
+ address = __connman_ipconfig_get_local(ipconfig_ipv4);
+ if (!address)
+ return -EINVAL;
+
+ connman_info("Starting ACD for address %s", address);
+ if (inet_pton(AF_INET, address, &addr) != 1)
+ connman_error("Could not convert address %s", address);
+
+ acd_host_start(network->acd_host, htonl(addr.s_addr));
+
+ return 0;
+}
+
static void dhcp_success(struct connman_network *network)
{
struct connman_service *service;
@@ -196,6 +462,14 @@ static void dhcp_success(struct connman_network *network)
if (!ipconfig_ipv4)
return;
+ if (connman_setting_get_bool("AddressConflictDetection")) {
+ err = start_acd(network);
+ if (!err)
+ return;
+
+ /* On error proceed without ACD. */
+ }
+
err = __connman_ipconfig_address_add(ipconfig_ipv4);
if (err < 0)
goto err;
@@ -266,6 +540,14 @@ static int set_connected_manual(struct connman_network *network)
if (!__connman_ipconfig_get_local(ipconfig))
__connman_service_read_ip4config(service);
+ if (connman_setting_get_bool("AddressConflictDetection")) {
+ err = start_acd(network);
+ if (!err)
+ return 0;
+
+ /* On error proceed without ACD. */
+ }
+
err = __connman_ipconfig_address_add(ipconfig);
if (err < 0)
goto err;
@@ -282,6 +564,14 @@ err:
return err;
}
+static void remove_dhcp_timeout(struct connman_network *network)
+{
+ if (network->dhcp_timeout > 0) {
+ g_source_remove(network->dhcp_timeout);
+ network->dhcp_timeout = 0;
+ }
+}
+
static int set_connected_dhcp(struct connman_network *network)
{
struct connman_service *service;
@@ -289,6 +579,7 @@ static int set_connected_dhcp(struct connman_network *network)
int err;
DBG("network %p", network);
+ remove_dhcp_timeout(network);
service = connman_service_lookup_from_network(network);
ipconfig_ipv4 = __connman_service_get_ip4config(service);
@@ -304,6 +595,44 @@ static int set_connected_dhcp(struct connman_network *network)
return 0;
}
+static gboolean set_connected_dhcp_timout(gpointer data)
+{
+ struct connman_network *network = data;
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig;
+ enum connman_ipconfig_method method;
+
+ network->dhcp_timeout = 0;
+
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return FALSE;
+
+ ipconfig = __connman_service_get_ip4config(service);
+ if (!ipconfig)
+ return FALSE;
+
+ /* Method is still DHCP? */
+ method = __connman_ipconfig_get_method(ipconfig);
+ if (method == CONNMAN_IPCONFIG_METHOD_DHCP)
+ set_connected_dhcp(network);
+
+ return FALSE;
+}
+
+void connman_network_set_connected_dhcp_later(struct connman_network *network,
+ uint32_t sec)
+{
+ remove_dhcp_timeout(network);
+
+ network->dhcp_timeout =
+ g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+ sec,
+ set_connected_dhcp_timout,
+ network,
+ NULL);
+}
+
static int manual_ipv6_set(struct connman_network *network,
struct connman_ipconfig *ipconfig_ipv6)
{
@@ -573,7 +902,6 @@ static void receive_refresh_rs_reply(struct nd_router_advert *reply,
network->router_solicit_refresh_count = 0;
connman_network_unref(network);
- return;
}
int __connman_network_refresh_rs_ipv6(struct connman_network *network,
@@ -730,6 +1058,7 @@ static void set_disconnected(struct connman_network *network)
__connman_service_notify_ipv4_configuration(service);
/* fall through */
case CONNMAN_IPCONFIG_METHOD_DHCP:
+ remove_dhcp_timeout(network);
__connman_dhcp_stop(ipconfig_ipv4);
break;
}
@@ -770,6 +1099,7 @@ static void set_disconnected(struct connman_network *network)
__connman_ipconfig_address_unset(ipconfig_ipv4);
__connman_ipconfig_address_unset(ipconfig_ipv6);
+
#if defined TIZEN_EXT
}
#endif
@@ -982,6 +1312,7 @@ static void network_destruct(struct connman_network *network)
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_slist_free_full(network->wifi.bssid_list, g_free);
@@ -991,6 +1322,7 @@ static void network_destruct(struct connman_network *network)
g_free(network->node);
g_free(network->name);
g_free(network->identifier);
+ acd_host_free(network->acd_host);
network->device = NULL;
@@ -1026,9 +1358,13 @@ struct connman_network *connman_network_create(const char *identifier,
network->type = type;
network->identifier = ident;
+ network->acd_host = NULL;
+ network->ipv4ll_timeout = 0;
network_list = g_slist_prepend(network_list, network);
+ network->dhcp_timeout = 0;
+
DBG("network %p identifier %s type %s", network, identifier,
type2string(type));
return network;
@@ -1559,7 +1895,6 @@ void connman_network_set_error(struct connman_network *network,
case CONNMAN_NETWORK_ERROR_BLOCKED:
set_blocked_error(network);
break;
-
}
__connman_network_disconnect(network);
@@ -1697,17 +2032,17 @@ int __connman_network_connect(struct connman_network *network)
if (!network->device)
return -ENODEV;
- network->connecting = true;
-
#if defined TIZEN_EXT
if (network->type != CONNMAN_NETWORK_TYPE_CELLULAR)
#endif
__connman_device_disconnect(network->device);
+
+ network->connecting = true;
+
#if defined TIZEN_EXT
DBG("ConnMan, Connect Request [%s]", network->name);
- struct connman_service *service = connman_service_lookup_from_network(network);
- connman_service_set_disconnection_requested(service, false);
#endif
+
err = network->driver->connect(network);
if (err < 0) {
if (err == -EINPROGRESS) {
@@ -1738,6 +2073,10 @@ int __connman_network_disconnect(struct connman_network *network)
DBG("network %p", network);
+ remove_ipv4ll_timeout(network);
+ if (network->acd_host)
+ acd_host_stop(network->acd_host);
+
if (!network->connected && !network->connecting &&
!network->associating)
return -ENOTCONN;
@@ -1746,6 +2085,7 @@ int __connman_network_disconnect(struct connman_network *network)
return -EUNATCH;
network->connecting = false;
+
#if defined TIZEN_EXT
DBG("ConnMan, Disconnect request");
struct connman_service *service = connman_service_lookup_from_network(network);
@@ -1781,13 +2121,16 @@ int __connman_network_clear_ipconfig(struct connman_network *network,
case CONNMAN_IPCONFIG_METHOD_OFF:
case CONNMAN_IPCONFIG_METHOD_FIXED:
return -EINVAL;
- case CONNMAN_IPCONFIG_METHOD_AUTO:
- release_dhcpv6(network);
- break;
case CONNMAN_IPCONFIG_METHOD_MANUAL:
__connman_ipconfig_address_remove(ipconfig);
break;
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ release_dhcpv6(network);
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ break;
+ /* fall through */
case CONNMAN_IPCONFIG_METHOD_DHCP:
+ remove_dhcp_timeout(network);
__connman_dhcp_stop(ipconfig_ipv4);
break;
}
@@ -2443,6 +2786,8 @@ int connman_network_set_bool(struct connman_network *network,
network->roaming = value;
else if (g_strcmp0(key, "WiFi.WPS") == 0)
network->wifi.wps = value;
+ else if (g_strcmp0(key, "WiFi.WPSAdvertising") == 0)
+ network->wifi.wps_advertizing = value;
else if (g_strcmp0(key, "WiFi.UseWPS") == 0)
network->wifi.use_wps = value;
#if defined TIZEN_EXT
@@ -2469,6 +2814,8 @@ bool connman_network_get_bool(struct connman_network *network,
return network->roaming;
else if (g_str_equal(key, "WiFi.WPS"))
return network->wifi.wps;
+ else if (g_str_equal(key, "WiFi.WPSAdvertising"))
+ return network->wifi.wps_advertizing;
else if (g_str_equal(key, "WiFi.UseWPS"))
return network->wifi.use_wps;
#if defined TIZEN_EXT
diff --git a/src/nostats.c b/src/nostats.c
new file mode 100644
index 00000000..aedc2c06
--- /dev/null
+++ b/src/nostats.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2018 Chris Novakovic
+ *
+ * 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 <errno.h>
+
+#include "connman.h"
+
+int __connman_stats_service_register(struct connman_service *service)
+{
+ return -ENOTSUP;
+}
+
+void __connman_stats_service_unregister(struct connman_service *service)
+{
+}
+
+int __connman_stats_update(struct connman_service *service,
+ bool roaming,
+ struct connman_stats_data *data)
+{
+ return 0;
+}
+
+int __connman_stats_get(struct connman_service *service,
+ bool roaming,
+ struct connman_stats_data *data)
+{
+ return 0;
+}
+
+int __connman_stats_init(void)
+{
+ return 0;
+}
+
+void __connman_stats_cleanup(void)
+{
+}
diff --git a/src/notifier.c b/src/notifier.c
index 7c3d0311..d1be47f6 100644
--- a/src/notifier.c
+++ b/src/notifier.c
@@ -50,11 +50,11 @@ static gint compare_priority(gconstpointer a, gconstpointer b)
*
* Returns: %0 on success
*/
-int connman_notifier_register(struct connman_notifier *notifier)
+int connman_notifier_register(const struct connman_notifier *notifier)
{
DBG("notifier %p name %s", notifier, notifier->name);
- notifier_list = g_slist_insert_sorted(notifier_list, notifier,
+ notifier_list = g_slist_insert_sorted(notifier_list, (void*)notifier,
compare_priority);
return 0;
@@ -66,7 +66,7 @@ int connman_notifier_register(struct connman_notifier *notifier)
*
* Remove a previously registered notifier module
*/
-void connman_notifier_unregister(struct connman_notifier *notifier)
+void connman_notifier_unregister(const struct connman_notifier *notifier)
{
DBG("notifier %p name %s", notifier, notifier->name);
@@ -221,7 +221,7 @@ void __connman_notifier_default_changed(struct connman_service *service)
GSList *list;
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->default_changed)
notifier->default_changed(service);
@@ -234,7 +234,7 @@ void __connman_notifier_service_add(struct connman_service *service,
GSList *list;
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->service_add)
notifier->service_add(service, name);
@@ -257,7 +257,7 @@ void __connman_notifier_service_remove(struct connman_service *service)
}
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->service_remove)
notifier->service_remove(service);
@@ -269,7 +269,7 @@ void __connman_notifier_proxy_changed(struct connman_service *service)
GSList *list;
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->proxy_changed)
notifier->proxy_changed(service);
@@ -295,7 +295,7 @@ void __connman_notifier_offlinemode(bool enabled)
state_changed();
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->offline_mode)
notifier->offline_mode(enabled);
@@ -309,7 +309,7 @@ static void notify_idle_state(bool idle)
DBG("idle %d", idle);
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->idle_state)
notifier->idle_state(idle);
@@ -324,7 +324,7 @@ void __connman_notifier_service_state_changed(struct connman_service *service,
bool found;
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->service_state_changed)
notifier->service_state_changed(service, state);
@@ -367,7 +367,7 @@ void __connman_notifier_ipconfig_changed(struct connman_service *service,
GSList *list;
for (list = notifier_list; list; list = list->next) {
- struct connman_notifier *notifier = list->data;
+ const struct connman_notifier *notifier = list->data;
if (notifier->ipconfig_changed)
notifier->ipconfig_changed(service, ipconfig);
diff --git a/src/ntp.c b/src/ntp.c
index 11512a02..e72a57c4 100755
--- a/src/ntp.c
+++ b/src/ntp.c
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
@@ -118,43 +117,55 @@ struct ntp_msg {
#define NTP_PRECISION_US -19
#define NTP_PRECISION_NS -29
-static guint channel_watch = 0;
-static struct timespec mtx_time;
-static int transmit_fd = 0;
-
-static char *timeserver = NULL;
-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, struct sockaddr *server, uint32_t timeout);
-
-static void next_server(void)
+struct ntp_data {
+ char *timeserver;
+ struct sockaddr_in6 timeserver_addr;
+ struct timespec mtx_time;
+ int transmit_fd;
+ gint timeout_id;
+ guint retries;
+ guint channel_watch;
+ gint poll_id;
+ uint32_t timeout;
+ __connman_ntp_cb_t cb;
+ void *user_data;
+};
+
+static struct ntp_data *ntp_data;
+
+static void free_ntp_data(struct ntp_data *nd)
{
- if (timeserver) {
- g_free(timeserver);
- timeserver = NULL;
- }
-
- __connman_timeserver_sync_next();
+ if (nd->poll_id)
+ g_source_remove(nd->poll_id);
+ if (nd->timeout_id)
+ g_source_remove(nd->timeout_id);
+ if (nd->channel_watch)
+ g_source_remove(nd->channel_watch);
+ if (nd->timeserver)
+ g_free(nd->timeserver);
+ g_free(nd);
}
+static void send_packet(struct ntp_data *nd, struct sockaddr *server,
+ uint32_t timeout);
+
static gboolean send_timeout(gpointer user_data)
{
- uint32_t timeout = GPOINTER_TO_UINT(user_data);
+ struct ntp_data *nd = user_data;
- DBG("send timeout %u (retries %d)", timeout, retries);
+ DBG("send timeout %u (retries %d)", nd->timeout, nd->retries);
- if (retries++ == NTP_SEND_RETRIES)
- next_server();
+ if (nd->retries++ == NTP_SEND_RETRIES)
+ nd->cb(false, nd->user_data);
else
- send_packet(transmit_fd, (struct sockaddr *)&timeserver_addr, timeout << 1);
+ send_packet(nd, (struct sockaddr *)&nd->timeserver_addr,
+ nd->timeout << 1);
return FALSE;
}
-static void send_packet(int fd, struct sockaddr *server, uint32_t timeout)
+static void send_packet(struct ntp_data *nd, struct sockaddr *server,
+ uint32_t timeout)
{
struct ntp_msg msg;
struct timeval transmit_timeval;
@@ -177,38 +188,28 @@ static void send_packet(int fd, struct sockaddr *server, uint32_t timeout)
if (server->sa_family == AF_INET) {
size = sizeof(struct sockaddr_in);
- addr = (void *)&(((struct sockaddr_in *)&timeserver_addr)->sin_addr);
+ addr = (void *)&(((struct sockaddr_in *)&nd->timeserver_addr)->sin_addr);
} else if (server->sa_family == AF_INET6) {
size = sizeof(struct sockaddr_in6);
- addr = (void *)&timeserver_addr.sin6_addr;
+ addr = (void *)&nd->timeserver_addr.sin6_addr;
} else {
- connman_error("Family is neither ipv4 nor ipv6");
+ DBG("Family is neither ipv4 nor ipv6");
+ nd->cb(false, nd->user_data);
return;
}
gettimeofday(&transmit_timeval, NULL);
- clock_gettime(CLOCK_MONOTONIC, &mtx_time);
+ clock_gettime(CLOCK_MONOTONIC, &nd->mtx_time);
msg.xmttime.seconds = htonl(transmit_timeval.tv_sec + OFFSET_1900_1970);
msg.xmttime.fraction = htonl(transmit_timeval.tv_usec * 1000);
- len = sendto(fd, &msg, sizeof(msg), MSG_DONTWAIT,
+ len = sendto(nd->transmit_fd, &msg, sizeof(msg), MSG_DONTWAIT,
server, size);
-
- if (len < 0) {
- connman_error("Time request for server %s failed (%d/%s)",
- inet_ntop(server->sa_family, addr, ipaddrstring, sizeof(ipaddrstring)),
- errno, strerror(errno));
-
- if (errno == ENETUNREACH)
- __connman_timeserver_sync_next();
-
- return;
- }
-
- if (len != sizeof(msg)) {
- connman_error("Broken time request for server %s",
+ if (len < 0 || len != sizeof(msg)) {
+ DBG("Time request for server %s failed",
inet_ntop(server->sa_family, addr, ipaddrstring, sizeof(ipaddrstring)));
+ nd->cb(false, nd->user_data);
return;
}
@@ -218,34 +219,35 @@ static void send_packet(int fd, struct sockaddr *server, uint32_t timeout)
* trying another server.
*/
- timeout_id = g_timeout_add_seconds(timeout, send_timeout,
- GUINT_TO_POINTER(timeout));
+ nd->timeout = timeout;
+ nd->timeout_id = g_timeout_add_seconds(timeout, send_timeout, nd);
}
static gboolean next_poll(gpointer user_data)
{
- poll_id = 0;
+ struct ntp_data *nd = user_data;
+ nd->poll_id = 0;
- if (!timeserver || transmit_fd == 0)
+ if (!nd->timeserver || nd->transmit_fd == 0)
return FALSE;
- send_packet(transmit_fd, (struct sockaddr *)&timeserver_addr, NTP_SEND_TIMEOUT);
+ send_packet(nd, (struct sockaddr *)&nd->timeserver_addr, NTP_SEND_TIMEOUT);
return FALSE;
}
-static void reset_timeout(void)
+static void reset_timeout(struct ntp_data *nd)
{
- if (timeout_id > 0) {
- g_source_remove(timeout_id);
- timeout_id = 0;
+ if (nd->timeout_id > 0) {
+ g_source_remove(nd->timeout_id);
+ nd->timeout_id = 0;
}
- retries = 0;
+ nd->retries = 0;
}
-static void decode_msg(void *base, size_t len, struct timeval *tv,
- struct timespec *mrx_time)
+static void decode_msg(struct ntp_data *nd, void *base, size_t len,
+ struct timeval *tv, struct timespec *mrx_time)
{
struct ntp_msg *msg = base;
double m_delta, org, rec, xmt, dst;
@@ -254,6 +256,7 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
#if !defined TIZEN_EXT
struct timex tmx = {};
#endif
+
if (len < sizeof(*msg)) {
connman_error("Invalid response from time server");
return;
@@ -281,9 +284,9 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
uint32_t code = ntohl(msg->refid);
connman_info("Skipping server %s KoD code %c%c%c%c",
- timeserver, code >> 24, code >> 16 & 0xff,
+ nd->timeserver, code >> 24, code >> 16 & 0xff,
code >> 8 & 0xff, code & 0xff);
- next_server();
+ nd->cb(false, nd->user_data);
return;
}
@@ -291,6 +294,7 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
if (NTP_FLAGS_LI_DECODE(msg->flags) == NTP_FLAG_LI_NOTINSYNC) {
DBG("ignoring unsynchronized peer");
+ nd->cb(false, nd->user_data);
return;
}
@@ -301,17 +305,19 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
NTP_FLAG_VN_VER4, NTP_FLAGS_VN_DECODE(msg->flags));
} else {
DBG("unsupported version %d", NTP_FLAGS_VN_DECODE(msg->flags));
+ nd->cb(false, nd->user_data);
return;
}
}
if (NTP_FLAGS_MD_DECODE(msg->flags) != NTP_FLAG_MD_SERVER) {
DBG("unsupported mode %d", NTP_FLAGS_MD_DECODE(msg->flags));
+ nd->cb(false, nd->user_data);
return;
}
- m_delta = mrx_time->tv_sec - mtx_time.tv_sec +
- 1.0e-9 * (mrx_time->tv_nsec - mtx_time.tv_nsec);
+ m_delta = mrx_time->tv_sec - nd->mtx_time.tv_sec +
+ 1.0e-9 * (mrx_time->tv_nsec - nd->mtx_time.tv_nsec);
org = tv->tv_sec + (1.0e-6 * tv->tv_usec) - m_delta + OFFSET_1900_1970;
rec = ntohl(msg->rectime.seconds) +
@@ -329,18 +335,19 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
/* Remove the timeout, as timeserver has responded */
- reset_timeout();
+ reset_timeout(nd);
/*
* Now poll the server every transmit_delay seconds
* for time correction.
*/
- if (poll_id > 0)
- g_source_remove(poll_id);
+ if (nd->poll_id > 0)
+ g_source_remove(nd->poll_id);
- DBG("Timeserver %s, next sync in %d seconds", timeserver, transmit_delay);
+ DBG("Timeserver %s, next sync in %d seconds", nd->timeserver,
+ transmit_delay);
- poll_id = g_timeout_add_seconds(transmit_delay, next_poll, NULL);
+ nd->poll_id = g_timeout_add_seconds(transmit_delay, next_poll, nd);
#if defined TIZEN_EXT
//send the dbus message to alram-manager
@@ -435,18 +442,22 @@ static void decode_msg(void *base, size_t len, struct timeval *tv,
tmx.status |= STA_DEL;
if (adjtimex(&tmx) < 0) {
- connman_error("Failed to adjust time");
+ connman_error("Failed to adjust time: %s (%d)", strerror(errno), errno);
+ nd->cb(false, nd->user_data);
return;
}
DBG("interval/delta/delay/drift %fs/%+.3fs/%.3fs/%+ldppm",
- LOGTOD(msg->poll), offset, delay, tmx.freq / 65536);
+ LOGTOD(msg->poll), offset, delay, tmx.freq / 65536);
+
+ nd->cb(true, nd->user_data);
#endif
}
static gboolean received_data(GIOChannel *channel, GIOCondition condition,
gpointer user_data)
{
+ struct ntp_data *nd = user_data;
unsigned char buf[128];
struct sockaddr_in6 sender_addr;
struct msghdr msg;
@@ -463,7 +474,7 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
connman_error("Problem with timer server channel");
- channel_watch = 0;
+ nd->channel_watch = 0;
return FALSE;
}
@@ -486,11 +497,11 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
if (sender_addr.sin6_family == AF_INET) {
size = 4;
- addr_ptr = &((struct sockaddr_in *)&timeserver_addr)->sin_addr;
+ addr_ptr = &((struct sockaddr_in *)&nd->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;
+ addr_ptr = &((struct sockaddr_in6 *)&nd->timeserver_addr)->sin6_addr;
src_ptr = &((struct sockaddr_in6 *)&sender_addr)->sin6_addr;
} else {
connman_error("Not a valid family type");
@@ -514,12 +525,12 @@ static gboolean received_data(GIOChannel *channel, GIOCondition condition,
}
}
- decode_msg(iov.iov_base, iov.iov_len, tv, &mrx_time);
+ decode_msg(nd, iov.iov_base, iov.iov_len, tv, &mrx_time);
return TRUE;
}
-static void start_ntp(char *server)
+static void start_ntp(struct ntp_data *nd)
{
GIOChannel *channel;
struct addrinfo hint;
@@ -532,14 +543,11 @@ static void start_ntp(char *server)
int tos = IPTOS_LOWDELAY, timestamp = 1;
int ret;
- if (!server)
- return;
-
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);
+ ret = getaddrinfo(nd->timeserver, NULL, &hint, &info);
if (ret) {
connman_error("cannot get server info");
@@ -548,18 +556,18 @@ static void start_ntp(char *server)
family = info->ai_family;
- memcpy(&timeserver_addr, info->ai_addr, info->ai_addrlen);
+ memcpy(&ntp_data->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);
+ ((struct sockaddr_in *)&ntp_data->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);
+ ntp_data->timeserver_addr.sin6_port = htons(123);
in6addr.sin6_family = family;
addr = (struct sockaddr *)&in6addr;
size = sizeof(in6addr);
@@ -568,96 +576,90 @@ static void start_ntp(char *server)
return;
}
- DBG("server %s family %d", server, family);
+ DBG("server %s family %d", nd->timeserver, family);
- if (channel_watch > 0)
+ if (nd->channel_watch > 0)
goto send;
- transmit_fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ nd->transmit_fd = socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (transmit_fd <= 0) {
- connman_error("Failed to open time server socket");
- return;
+ if (nd->transmit_fd <= 0) {
+ if (errno != EAFNOSUPPORT)
+ connman_error("Failed to open time server socket");
}
- if (bind(transmit_fd, (struct sockaddr *) addr, size) < 0) {
+ if (bind(nd->transmit_fd, (struct sockaddr *) addr, size) < 0) {
connman_error("Failed to bind time server socket");
- close(transmit_fd);
- return;
+ goto err;
}
if (family == AF_INET) {
- if (setsockopt(transmit_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
+ if (setsockopt(nd->transmit_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
connman_error("Failed to set type of service option");
- close(transmit_fd);
- return;
+ goto err;
}
}
- if (setsockopt(transmit_fd, SOL_SOCKET, SO_TIMESTAMP, &timestamp,
+ if (setsockopt(nd->transmit_fd, SOL_SOCKET, SO_TIMESTAMP, &timestamp,
sizeof(timestamp)) < 0) {
connman_error("Failed to enable timestamp support");
- close(transmit_fd);
- return;
+ goto err;
}
- channel = g_io_channel_unix_new(transmit_fd);
- if (!channel) {
- close(transmit_fd);
- return;
- }
+ channel = g_io_channel_unix_new(nd->transmit_fd);
+ if (!channel)
+ goto err;
g_io_channel_set_encoding(channel, NULL, NULL);
g_io_channel_set_buffered(channel, FALSE);
g_io_channel_set_close_on_unref(channel, TRUE);
- channel_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
+ nd->channel_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- received_data, NULL, NULL);
+ received_data, nd, NULL);
g_io_channel_unref(channel);
send:
- send_packet(transmit_fd, (struct sockaddr*)&timeserver_addr, NTP_SEND_TIMEOUT);
+ send_packet(nd, (struct sockaddr*)&ntp_data->timeserver_addr,
+ NTP_SEND_TIMEOUT);
+ return;
+
+err:
+ if (nd->transmit_fd > 0)
+ close(nd->transmit_fd);
+
+ nd->cb(false, nd->user_data);
}
-int __connman_ntp_start(char *server)
+int __connman_ntp_start(char *server, __connman_ntp_cb_t callback,
+ void *user_data)
{
- DBG("%s", server);
-
if (!server)
return -EINVAL;
- if (timeserver)
- g_free(timeserver);
+ if (ntp_data) {
+ connman_warn("ntp_data is not NULL (timerserver %s)",
+ ntp_data->timeserver);
+ free_ntp_data(ntp_data);
+ }
+
+ ntp_data = g_new0(struct ntp_data, 1);
- timeserver = g_strdup(server);
+ ntp_data->timeserver = g_strdup(server);
+ ntp_data->cb = callback;
+ ntp_data->user_data = user_data;
- start_ntp(timeserver);
+ start_ntp(ntp_data);
return 0;
}
void __connman_ntp_stop()
{
- DBG("");
-
- if (poll_id > 0) {
- g_source_remove(poll_id);
- poll_id = 0;
- }
-
- reset_timeout();
-
- if (channel_watch > 0) {
- g_source_remove(channel_watch);
- channel_watch = 0;
- transmit_fd = 0;
- }
-
- if (timeserver) {
- g_free(timeserver);
- timeserver = NULL;
+ if (ntp_data) {
+ free_ntp_data(ntp_data);
+ ntp_data = NULL;
}
}
diff --git a/src/peer.c b/src/peer.c
index 340cbcc2..2102f119 100755
--- a/src/peer.c
+++ b/src/peer.c
@@ -82,7 +82,7 @@ static void stop_dhcp_server(struct connman_peer *peer)
peer->dhcp_server = NULL;
if (peer->ip_pool)
- __connman_ippool_unref(peer->ip_pool);
+ __connman_ippool_free(peer->ip_pool);
peer->ip_pool = NULL;
peer->lease_ip = 0;
}
@@ -606,6 +606,9 @@ static int peer_connect(struct connman_peer *peer)
{
int err = -ENOTSUP;
+ if (is_connected(peer))
+ return -EISCONN;
+
if (peer_driver->connect)
err = peer_driver->connect(peer,
CONNMAN_PEER_WPS_UNKNOWN, NULL);
@@ -1177,6 +1180,18 @@ const char *__connman_peer_get_path(struct connman_peer *peer)
return peer->path;
}
+static void disconnect_peer_hash_table(gpointer key,
+ gpointer value, gpointer user_data)
+{
+ struct connman_peer *peer = value;
+ peer_disconnect(peer);
+}
+
+void __connman_peer_disconnect_all(void)
+{
+ g_hash_table_foreach(peers_table, disconnect_peer_hash_table, NULL);
+}
+
int __connman_peer_init(void)
{
DBG("");
diff --git a/src/provider.c b/src/provider.c
index c0d69e49..f1e4a067 100755
--- a/src/provider.c
+++ b/src/provider.c
@@ -742,7 +742,7 @@ static void provider_service_changed(struct connman_service *service,
vpn_index = __connman_connection_get_vpn_index(service_index);
DBG("service %p %s state %d index %d/%d", service,
- __connman_service_get_ident(service),
+ connman_service_get_identifier(service),
state, service_index, vpn_index);
if (vpn_index < 0)
@@ -755,11 +755,9 @@ static void provider_service_changed(struct connman_service *service,
DBG("disconnect %p index %d", provider, vpn_index);
connman_provider_disconnect(provider);
-
- return;
}
-static struct connman_notifier provider_notifier = {
+static const struct connman_notifier provider_notifier = {
.name = "provider",
.offline_mode = provider_offline_mode,
.service_state_changed = provider_service_changed,
diff --git a/src/resolver.c b/src/resolver.c
index d6c20cdd..7ec2150b 100755
--- a/src/resolver.c
+++ b/src/resolver.c
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
@@ -35,6 +34,19 @@
#include "connman.h"
+/*
+ * Just to avoid build failure due to missing STATEDIR
+ */
+#if defined TIZEN_EXT
+#ifdef STATEDIR
+#undef STATEDIR
+#endif
+#define STATEDIR "/etc"
+#endif
+
+#define RESOLV_CONF_STATEDIR STATEDIR"/resolv.conf"
+#define RESOLV_CONF_ETC "/etc/resolv.conf"
+
#define RESOLVER_FLAG_PUBLIC (1 << 0)
/*
@@ -130,11 +142,19 @@ static int resolvfile_export(void)
old_umask = umask(022);
- fd = open("/etc/resolv.conf", O_RDWR | O_CREAT | O_CLOEXEC,
+ fd = open(RESOLV_CONF_STATEDIR, O_RDWR | O_CREAT | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd < 0) {
- err = -errno;
- goto done;
+ connman_warn_once("Cannot create "RESOLV_CONF_STATEDIR" "
+ "falling back to "RESOLV_CONF_ETC);
+
+ fd = open(RESOLV_CONF_ETC, O_RDWR | O_CREAT | O_CLOEXEC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (fd < 0) {
+ err = -errno;
+ goto done;
+ }
}
if (ftruncate(fd, 0) < 0) {
@@ -658,6 +678,14 @@ static void free_resolvfile(gpointer data)
g_free(entry);
}
+int __connman_resolver_set_mdns(int index, bool enabled)
+{
+ if (!dnsproxy_enabled)
+ return -ENOTSUP;
+
+ return __connman_dnsproxy_set_mdns(index, enabled);
+}
+
int __connman_resolver_init(gboolean dnsproxy)
{
int i;
diff --git a/src/rfkill.c b/src/rfkill.c
index fce9d720..99b337d2 100755
--- a/src/rfkill.c
+++ b/src/rfkill.c
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/src/rtnl.c b/src/rtnl.c
index d7332880..aa5c07cc 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -167,6 +167,7 @@ static void read_uevent(struct interface_data *interface)
if (ether_blacklisted(name)) {
interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN;
+ goto out;
} else {
interface->service_type = CONNMAN_SERVICE_TYPE_ETHERNET;
interface->device_type = CONNMAN_DEVICE_TYPE_ETHERNET;
@@ -1381,10 +1382,10 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr)
DBG("service: %p\n",service);
#endif
servers = rtnl_nd_opt_rdnss(opt, &lifetime,
- &nr_servers);
+ &nr_servers);
for (i = 0; i < nr_servers; i++) {
if (!inet_ntop(AF_INET6, servers + i, buf,
- sizeof(buf)))
+ sizeof(buf)))
continue;
#if defined TIZEN_EXT
@@ -1396,7 +1397,7 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr)
CONNMAN_IPCONFIG_TYPE_IPV6);
#endif
connman_resolver_append_lifetime(index,
- NULL, buf, lifetime);
+ NULL, buf, lifetime);
}
} else if (opt->nd_opt_type == 31) { /* ND_OPT_DNSSL */
@@ -1531,7 +1532,7 @@ static void rtnl_message(void *buf, size_t len)
if (!NLMSG_OK(hdr, len))
break;
- DBG("%s len %d type %d flags 0x%04x seq %d pid %d",
+ DBG("%s len %u type %u flags 0x%04x seq %u pid %u",
type2string(hdr->nlmsg_type),
hdr->nlmsg_len, hdr->nlmsg_type,
hdr->nlmsg_flags, hdr->nlmsg_seq,
diff --git a/src/service.c b/src/service.c
index 47c828d8..0c6e6235 100644
--- a/src/service.c
+++ b/src/service.c
@@ -30,8 +30,6 @@
#include <gdbus.h>
#include <ctype.h>
#include <stdint.h>
-#include <pwd.h>
-#include <utmpx.h>
#include <connman/storage.h>
#include <connman/setting.h>
@@ -41,9 +39,6 @@
#define CONNECT_TIMEOUT 120
-#define USER_ROOT 0
-#define USER_NONE (uid_t)-1
-
#if defined TIZEN_EXT
#define WIFI_BSSID_STR_LEN 18
#endif
@@ -53,8 +48,8 @@ static DBusConnection *connection = NULL;
static GList *service_list = NULL;
static GHashTable *service_hash = NULL;
static GSList *counter_list = NULL;
-static unsigned int autoconnect_timeout = 0;
-static unsigned int vpn_autoconnect_timeout = 0;
+static unsigned int autoconnect_id = 0;
+static unsigned int vpn_autoconnect_id = 0;
static struct connman_service *current_default = NULL;
static bool services_dirty = false;
@@ -76,11 +71,6 @@ struct connman_stats_counter {
struct connman_stats stats_roaming;
};
-struct connman_service_user {
- uid_t favorite_user;
- uid_t current_user;
-};
-
struct connman_service {
int refcount;
char *identifier;
@@ -103,8 +93,6 @@ struct connman_service {
char *name;
char *passphrase;
bool roaming;
- bool request_passphrase_input;
- struct connman_service_user user;
struct connman_ipconfig *ipconfig_ipv4;
struct connman_ipconfig *ipconfig_ipv6;
struct connman_network *network;
@@ -114,6 +102,8 @@ struct connman_service {
char **nameservers_auto;
int nameservers_timeout;
char **domains;
+ bool mdns;
+ bool mdns_config;
char *hostname;
char *domainname;
char **timeservers;
@@ -144,7 +134,10 @@ struct connman_service {
char **excludes;
char *pac;
bool wps;
- int online_check_count;
+ bool wps_advertizing;
+ guint online_timeout;
+ int online_check_interval_ipv4;
+ int online_check_interval_ipv6;
bool do_split_routing;
bool new_service;
bool hidden_service;
@@ -497,89 +490,6 @@ static enum connman_dnsconfig_method __connman_dnsconfig_string2method(
}
#endif
-static bool
-connman_service_is_user_allowed(struct connman_service *service, uid_t uid)
-{
- uid_t favorite_user = service->user.favorite_user;
- uid_t current_user = uid;
-
- DBG("Service favorite UID: %d, current UID: %d", favorite_user, current_user);
- if (favorite_user == USER_NONE || current_user == USER_ROOT)
- return true;
-
- if (favorite_user != current_user || current_user == USER_NONE) {
- DBG("Current user is not a favorite user to this service!");
- return false;
- }
-
- return true;
-}
-
-#if !defined TIZEN_EXT
-static GList *connman_service_get_login_users()
-{
- struct utmpx *utmp;
- struct passwd *pwd;
- GList *user_list = NULL;
-
- setutxent();
-
- while ((utmp = getutxent()) != NULL) {
- DBG("User Name: %s", utmp->ut_user);
-
- pwd = getpwnam(utmp->ut_user);
- if (pwd) {
- if (!g_list_find(user_list, GUINT_TO_POINTER(pwd->pw_uid)))
- user_list = g_list_append(user_list,
- GUINT_TO_POINTER(pwd->pw_uid));
-
- DBG("User Name: %s, UID: %d", utmp->ut_user, pwd->pw_uid);
- }
- }
-
- endutxent();
-
- return user_list;
-}
-#endif
-
-static bool is_service_owner_user_login(struct connman_service *service)
-{
-#if defined TIZEN_EXT
- return true;
-#else
- GList *list, *user_list;
- bool ret = false;
-
- /* Here we only care about wifi service */
- if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
- return true;
-
- DBG("service favorite user id is: %d", service->user.favorite_user);
-
- user_list = connman_service_get_login_users();
- if (user_list == NULL) {
- DBG("Can not get any logged in user info.");
- return true;
- }
-
- for (list = user_list; list; list = list->next) {
- uid_t uid = GPOINTER_TO_UINT(list->data);
-
- DBG("login user id is %d", uid);
-
- if (service->user.favorite_user == uid) {
- ret = true;
- break;
- }
- }
-
- g_list_free(user_list);
-
- return ret;
-#endif
-}
-
static void set_split_routing(struct connman_service *service, bool value)
{
if (service->type != CONNMAN_SERVICE_TYPE_VPN)
@@ -646,25 +556,6 @@ int __connman_service_load_modifiable(struct connman_service *service)
return 0;
}
-static int service_load_passphrase(struct connman_service *service)
-{
- GKeyFile *keyfile;
- gchar *str;
-
- keyfile = connman_storage_load_service(service->identifier);
- if (!keyfile)
- return -EIO;
-
- str = g_key_file_get_string(keyfile,
- service->identifier, "Passphrase", NULL);
- if (str)
- service->passphrase = str;
-
- g_key_file_free(keyfile);
-
- return 0;
-}
-
static int service_load(struct connman_service *service)
{
GKeyFile *keyfile;
@@ -862,6 +753,9 @@ static int service_load(struct connman_service *service)
service->pac = str;
}
+ service->mdns_config = g_key_file_get_boolean(keyfile,
+ service->identifier, "mDNS", NULL);
+
service->hidden_service = g_key_file_get_boolean(keyfile,
service->identifier, "Hidden", NULL);
@@ -919,9 +813,6 @@ static int service_load(struct connman_service *service)
}
#endif
- if (g_key_file_has_key(keyfile, service->identifier, "UID", NULL))
- service->user.favorite_user = g_key_file_get_integer(keyfile,
- service->identifier, "UID", NULL);
done:
g_key_file_free(keyfile);
@@ -970,13 +861,6 @@ static int service_save(struct connman_service *service)
const unsigned char *ssid;
unsigned int ssid_len = 0;
- if (service->user.favorite_user == USER_NONE)
- g_key_file_remove_key(keyfile, service->identifier,
- "UID", NULL);
- else
- g_key_file_set_integer(keyfile, service->identifier,
- "UID", service->user.favorite_user);
-
ssid = connman_network_get_blob(service->network,
"WiFi.SSID", &ssid_len);
@@ -1032,14 +916,12 @@ static int service_save(struct connman_service *service)
g_free(str);
}
- if (service->user.current_user == service->user.favorite_user) {
- if (service->passphrase && strlen(service->passphrase) > 0)
- g_key_file_set_string(keyfile, service->identifier,
+ if (service->passphrase && strlen(service->passphrase) > 0)
+ g_key_file_set_string(keyfile, service->identifier,
"Passphrase", service->passphrase);
- else
- g_key_file_remove_key(keyfile, service->identifier,
- "Passphrase", NULL);
- }
+ else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Passphrase", NULL);
if (service->ipconfig_ipv4)
__connman_ipconfig_save(service->ipconfig_ipv4, keyfile,
@@ -1133,6 +1015,13 @@ static int service_save(struct connman_service *service)
g_key_file_remove_key(keyfile, service->identifier,
"Proxy.URL", NULL);
+ if (service->mdns_config)
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "mDNS", TRUE);
+ else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "mDNS", NULL);
+
if (service->hidden_service)
g_key_file_set_boolean(keyfile, service->identifier, "Hidden",
TRUE);
@@ -1646,6 +1535,7 @@ static int nameserver_remove_all(struct connman_service *service,
return -ENXIO;
while (service->nameservers_config && service->nameservers_config[i]) {
+
#if defined TIZEN_EXT
DBG("type %d Remove service->nameservers_config[%d]: %s",
type, i, service->nameservers_config[i]);
@@ -1789,7 +1679,7 @@ int __connman_service_nameserver_append(struct connman_service *service,
char **nameservers;
int len, i;
- DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
+ DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
if (!nameserver)
return -EINVAL;
@@ -2050,7 +1940,7 @@ static void address_updated(struct connman_service *service,
enum connman_ipconfig_type type)
{
if (is_connected(service->state) &&
- service == __connman_service_get_default()) {
+ service == connman_service_get_default()) {
nameserver_remove_all(service, type);
nameserver_add_all(service, type);
@@ -2160,19 +2050,6 @@ static gboolean __connman_service_is_internet_profile(
return FALSE;
}
-static gboolean __connman_service_is_tethering_profile(
- struct connman_service *cellular)
-{
- const char tethering_suffix[] = "_5";
-
- DBG("Service path: %s", cellular->path);
-
- if (g_str_has_suffix(cellular->path, tethering_suffix) == TRUE)
- return TRUE;
-
- return FALSE;
-}
-
struct connman_service *connman_service_get_default_connection(void)
{
GList *list;
@@ -2216,7 +2093,7 @@ struct connman_service *connman_service_get_default_connection(void)
}
#endif
-struct connman_service *__connman_service_get_default(void)
+struct connman_service *connman_service_get_default(void)
{
#if defined TIZEN_MAINTAIN_ONLINE
return connman_service_get_default_connection();
@@ -2242,14 +2119,14 @@ bool __connman_service_index_is_default(int index)
if (index < 0)
return false;
- service = __connman_service_get_default();
+ service = connman_service_get_default();
return __connman_service_get_index(service) == index;
}
static void default_changed(void)
{
- struct connman_service *service = __connman_service_get_default();
+ struct connman_service *service = connman_service_get_default();
if (service == current_default)
return;
@@ -2273,7 +2150,8 @@ static void default_changed(void)
connman_setting_get_bool("AllowHostnameUpdates"))
__connman_utsname_set_hostname(service->hostname);
- if (service->domainname)
+ if (service->domainname &&
+ connman_setting_get_bool("AllowDomainnameUpdates"))
__connman_utsname_set_domainname(service->domainname);
}
@@ -2293,6 +2171,7 @@ static void state_changed(struct connman_service *service)
#if !defined TIZEN_EXT
if (!allow_property_changed(service))
return;
+
#endif
#if defined TIZEN_EXT
DBG(" %s, %s", str, service->path);
@@ -2451,15 +2330,37 @@ static void append_security(DBusMessageIter *iter, void *user_data)
dbus_message_iter_append_basic(iter,
DBUS_TYPE_STRING, &str);
break;
+#if defined TIZEN_EXT
+ case CONNMAN_SERVICE_SECURITY_OWE:
+#endif
case CONNMAN_SERVICE_SECURITY_UNKNOWN:
case CONNMAN_SERVICE_SECURITY_NONE:
case CONNMAN_SERVICE_SECURITY_WEP:
case CONNMAN_SERVICE_SECURITY_8021X:
break;
}
+
+ if (service->wps_advertizing) {
+ str = "wps_advertising";
+ dbus_message_iter_append_basic(iter,
+ DBUS_TYPE_STRING, &str);
+ }
}
}
+static void security_changed(struct connman_service *service)
+{
+ if (!service->path)
+ return;
+
+ if (!allow_property_changed(service))
+ return;
+
+ connman_dbus_property_changed_array(service->path,
+ CONNMAN_SERVICE_INTERFACE, "Security",
+ DBUS_TYPE_STRING, append_security, service);
+}
+
static void append_ethernet(DBusMessageIter *iter, void *user_data)
{
struct connman_service *service = user_data;
@@ -3039,6 +2940,48 @@ static void proxy_configuration_changed(struct connman_service *service)
proxy_changed(service);
}
+static void mdns_changed(struct connman_service *service)
+{
+ dbus_bool_t mdns = service->mdns;
+
+ if (!allow_property_changed(service))
+ return;
+
+ connman_dbus_property_changed_basic(service->path,
+ CONNMAN_SERVICE_INTERFACE, "mDNS", DBUS_TYPE_BOOLEAN,
+ &mdns);
+}
+
+static void mdns_configuration_changed(struct connman_service *service)
+{
+ dbus_bool_t mdns_config = service->mdns_config;
+
+ if (!allow_property_changed(service))
+ return;
+
+ connman_dbus_property_changed_basic(service->path,
+ CONNMAN_SERVICE_INTERFACE, "mDNS.Configuration",
+ DBUS_TYPE_BOOLEAN, &mdns_config);
+}
+
+static int set_mdns(struct connman_service *service,
+ bool enabled)
+{
+ int result;
+
+ result = __connman_resolver_set_mdns(
+ __connman_service_get_index(service), enabled);
+
+ if (result == 0) {
+ if (service->mdns != enabled) {
+ service->mdns = enabled;
+ mdns_changed(service);
+ }
+ }
+
+ return result;
+}
+
static void timeservers_configuration_changed(struct connman_service *service)
{
if (!allow_property_changed(service))
@@ -3289,17 +3232,16 @@ void __connman_service_counter_unregister(const char *counter)
counter_list = g_slist_remove(counter_list, counter);
}
-int __connman_service_iterate_services(service_iterate_cb cb, void *user_data)
+int connman_service_iterate_services(connman_service_iterate_cb cb,
+ void *user_data)
{
GList *list;
+ int ret = 0;
- for (list = service_list; list; list = list->next) {
- struct connman_service *service = list->data;
+ for (list = service_list; list && ret == 0; list = list->next)
+ ret = cb((struct connman_service *)list->data, user_data);
- cb(service, user_data);
- }
-
- return 0;
+ return ret;
}
#if defined TIZEN_EXT
@@ -3602,8 +3544,19 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
append_proxyconfig, service);
+ val = service->mdns;
+ connman_dbus_dict_append_basic(dict, "mDNS", DBUS_TYPE_BOOLEAN,
+ &val);
+
+ val = service->mdns_config;
+ connman_dbus_dict_append_basic(dict, "mDNS.Configuration",
+ DBUS_TYPE_BOOLEAN, &val);
+
connman_dbus_dict_append_dict(dict, "Provider",
append_provider, service);
+
+ if (service->network)
+ connman_network_append_acddbus(dict, service->network);
}
static void append_struct_service(DBusMessageIter *iter,
@@ -3701,7 +3654,10 @@ void __connman_service_set_hostname(struct connman_service *service,
return;
g_free(service->hostname);
- service->hostname = g_strdup(hostname);
+ service->hostname = NULL;
+
+ if (hostname && g_str_is_ascii(hostname))
+ service->hostname = g_strdup(hostname);
}
const char *__connman_service_get_hostname(struct connman_service *service)
@@ -3719,7 +3675,10 @@ void __connman_service_set_domainname(struct connman_service *service,
return;
g_free(service->domainname);
- service->domainname = g_strdup(domainname);
+ service->domainname = NULL;
+
+ if (domainname && g_str_is_ascii(domainname))
+ service->domainname = g_strdup(domainname);
domain_changed(service);
}
@@ -3735,6 +3694,14 @@ const char *connman_service_get_domainname(struct connman_service *service)
return service->domainname;
}
+const char *connman_service_get_dbuspath(struct connman_service *service)
+{
+ if (!service)
+ return NULL;
+
+ return service->path;
+}
+
char **connman_service_get_nameservers(struct connman_service *service)
{
if (!service)
@@ -4235,6 +4202,9 @@ int __connman_service_check_passphrase(enum connman_service_security security,
break;
case CONNMAN_SERVICE_SECURITY_8021X:
+#if defined TIZEN_EXT
+ case CONNMAN_SERVICE_SECURITY_OWE:
+#endif
break;
}
@@ -4252,6 +4222,7 @@ int __connman_service_set_passphrase(struct connman_service *service,
if (service->immutable &&
service->security != CONNMAN_SERVICE_SECURITY_8021X)
return -EINVAL;
+
#if defined TIZEN_EXT
/* The encrypted passphrase is used here
* and validation is done by net-config before being encrypted.
@@ -4561,7 +4532,7 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
*new_state = service->state_ipv6;
settings_changed(service, new_ipconfig);
- address_updated(service, new_method);
+ address_updated(service, type);
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
}
@@ -4573,6 +4544,29 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
return err;
}
+/*
+ * We set the timeout to 1 sec so that we have a chance to get
+ * necessary IPv6 router advertisement messages that might have
+ * DNS data etc.
+ */
+#define ONLINE_CHECK_INITIAL_INTERVAL 1
+#define ONLINE_CHECK_MAX_INTERVAL 12
+
+void __connman_service_wispr_start(struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ DBG("service %p type %s", service, __connman_ipconfig_type2string(type));
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ service->online_check_interval_ipv4 =
+ ONLINE_CHECK_INITIAL_INTERVAL;
+ else
+ service->online_check_interval_ipv6 =
+ ONLINE_CHECK_INITIAL_INTERVAL;
+
+ __connman_wispr_start(service, type);
+}
+
static DBusMessage *set_property(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -4589,21 +4583,6 @@ 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->state)) {
- uid_t uid;
- if (connman_dbus_get_connection_unix_user_sync(conn,
- dbus_message_get_sender(msg),
- &uid) < 0) {
- DBG("Can not get unix user id!");
- return __connman_error_permission_denied(msg);
- }
-
- if (!connman_service_is_user_allowed(service, uid)) {
- DBG("Not allow this user to operate this wifi service now!");
- return __connman_error_permission_denied(msg);
- }
- }
-
dbus_message_iter_get_basic(&iter, &name);
dbus_message_iter_next(&iter);
@@ -4665,6 +4644,7 @@ static DBusMessage *set_property(DBusConnection *conn,
if (gw && strlen(gw))
__connman_service_nameserver_del_routes(service,
CONNMAN_IPCONFIG_TYPE_ALL);
+
#endif
dbus_message_iter_recurse(&value, &entry);
@@ -4775,13 +4755,11 @@ static DBusMessage *set_property(DBusConnection *conn,
if (__connman_service_is_connected_state(service,
CONNMAN_IPCONFIG_TYPE_IPV4))
- __connman_wispr_start(service,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
if (__connman_service_is_connected_state(service,
CONNMAN_IPCONFIG_TYPE_IPV6))
- __connman_wispr_start(service,
- CONNMAN_IPCONFIG_TYPE_IPV6);
+ __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
service_save(service);
} else if (g_str_equal(name, "Timeservers.Configuration")) {
@@ -4821,15 +4799,14 @@ static DBusMessage *set_property(DBusConnection *conn,
char **timeservers = g_strsplit_set(str->str, " ", 0);
timeservers = remove_empty_strings(timeservers);
service->timeservers_config = timeservers;
- } else
- service->timeservers = NULL;
+ }
g_string_free(str, TRUE);
service_save(service);
timeservers_configuration_changed(service);
- if (service == __connman_service_get_default())
+ if (service == connman_service_get_default())
__connman_timeserver_sync(service);
} else if (g_str_equal(name, "Domains.Configuration")) {
@@ -4898,6 +4875,23 @@ static DBusMessage *set_property(DBusConnection *conn,
__connman_notifier_proxy_changed(service);
service_save(service);
+ } else if (g_str_equal(name, "mDNS.Configuration")) {
+ dbus_bool_t val;
+
+ if (service->immutable)
+ return __connman_error_not_supported(msg);
+
+ if (type != DBUS_TYPE_BOOLEAN)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&value, &val);
+ service->mdns_config = val;
+
+ mdns_configuration_changed(service);
+
+ set_mdns(service, service->mdns_config);
+
+ service_save(service);
} else if (g_str_equal(name, "IPv4.Configuration") ||
g_str_equal(name, "IPv6.Configuration")) {
@@ -5036,14 +5030,6 @@ static void service_complete(struct connman_service *service)
service_save(service);
}
-static void set_idle(struct connman_service *service)
-{
- service->state = service->state_ipv4 = service->state_ipv6 =
- CONNMAN_SERVICE_STATE_IDLE;
- set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
- state_changed(service);
-}
-
static DBusMessage *clear_property(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -5080,7 +5066,8 @@ static bool is_ignore(struct connman_service *service)
if (!service->autoconnect)
return true;
- if (service->roaming)
+ if (service->roaming &&
+ !connman_setting_get_bool("AutoConnectRoamingServices"))
return true;
if (service->ignore)
@@ -5358,11 +5345,6 @@ static bool auto_connect_service(GList *services,
continue;
}
- if (!is_service_owner_user_login(service)) {
- DBG("favorite user not login, wifi auto connect denied");
- continue;
- }
-
DBG("service %p %s %s", service, service->name,
(preferred) ? "preferred" : reason2string(reason));
@@ -5383,7 +5365,7 @@ static gboolean run_auto_connect(gpointer data)
bool autoconnecting = false;
GList *preferred_tech;
- autoconnect_timeout = 0;
+ autoconnect_id = 0;
DBG("");
@@ -5419,7 +5401,7 @@ void __connman_service_auto_connect(enum connman_service_connect_reason reason)
{
DBG("");
- if (autoconnect_timeout != 0)
+ if (autoconnect_id != 0)
return;
#if defined TIZEN_EXT
@@ -5445,9 +5427,9 @@ void __connman_service_auto_connect(enum connman_service_connect_reason reason)
* FAILURE state due to this when connection with AP2 is cancelled
* then autoconnect with AP1 doesn't works because its autoconnection
* is ignored as its last state was FAILURE rather than IDLE */
- autoconnect_timeout = g_timeout_add(500, run_auto_connect,
+ autoconnect_id = g_timeout_add(500, run_auto_connect,
#else
- autoconnect_timeout = g_idle_add(run_auto_connect,
+ autoconnect_id = g_idle_add(run_auto_connect,
#endif
GUINT_TO_POINTER(reason));
}
@@ -5456,7 +5438,7 @@ static gboolean run_vpn_auto_connect(gpointer data) {
GList *list;
bool need_split = false;
- vpn_autoconnect_timeout = 0;
+ vpn_autoconnect_id = 0;
for (list = service_list; list; list = list->next) {
struct connman_service *service = list->data;
@@ -5498,10 +5480,10 @@ static gboolean run_vpn_auto_connect(gpointer data) {
static void vpn_auto_connect(void)
{
- if (vpn_autoconnect_timeout)
+ if (vpn_autoconnect_id)
return;
- vpn_autoconnect_timeout =
+ vpn_autoconnect_id =
g_idle_add(run_vpn_auto_connect, NULL);
}
@@ -5527,7 +5509,6 @@ void __connman_service_set_provider_pending(struct connman_service *service,
}
service->provider_pending = msg;
- return;
}
static void check_pending_msg(struct connman_service *service)
@@ -5641,31 +5622,6 @@ static DBusMessage *connect_service(DBusConnection *conn,
if (service->pending)
return __connman_error_in_progress(msg);
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
- uid_t uid;
- if (connman_dbus_get_connection_unix_user_sync(conn,
- dbus_message_get_sender(msg),
- &uid) < 0) {
- DBG("Can not get unix user id!");
- return __connman_error_permission_denied(msg);
- }
-
- if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
- DBG("Not allow this user to connect this wifi service now!");
- return __connman_error_permission_denied(msg);
- }
-
- if (uid != USER_ROOT && uid != service->user.favorite_user)
- service->request_passphrase_input = true;
-
- service->user.current_user = uid;
-
- if (!service->passphrase && uid == service->user.favorite_user) {
- DBG("Now load this favorite user's passphrase.");
- service_load_passphrase(service);
- }
- }
-
#if !defined TIZEN_EXT
index = __connman_service_get_index(service);
@@ -5701,18 +5657,10 @@ static DBusMessage *connect_service(DBusConnection *conn,
err = __connman_service_connect(service,
CONNMAN_SERVICE_CONNECT_REASON_USER);
- if (err == -EINPROGRESS)
- return NULL;
-
- if (service->pending) {
- dbus_message_unref(service->pending);
- service->pending = NULL;
- }
-
- if (err < 0)
- return __connman_error_failed(msg, -err);
+ if (err != -EINPROGRESS)
+ reply_pending(service, -err);
- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ return NULL;
}
static DBusMessage *disconnect_service(DBusConnection *conn,
@@ -5737,21 +5685,6 @@ static DBusMessage *disconnect_service(DBusConnection *conn,
}
#endif
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
- uid_t uid;
- if (connman_dbus_get_connection_unix_user_sync(conn,
- dbus_message_get_sender(msg),
- &uid) < 0) {
- DBG("Can not get unix user id!");
- return __connman_error_permission_denied(msg);
- }
-
- if (!connman_service_is_user_allowed(service, uid)) {
- DBG("Not allow this user to disconnect this wifi service now!");
- return __connman_error_permission_denied(msg);
- }
- }
-
service->ignore = true;
err = __connman_service_disconnect(service);
@@ -5853,15 +5786,8 @@ bool __connman_service_remove(struct connman_service *service)
#endif
-#if defined TIZEN_EXT
- if (service->security != CONNMAN_SERVICE_SECURITY_8021X)
-#endif
- set_idle(service);
-
service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
- service->user.favorite_user = USER_NONE;
-
__connman_service_set_favorite(service, false);
__connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
@@ -5891,23 +5817,6 @@ static DBusMessage *remove_service(DBusConnection *conn,
DBG("service %p", service);
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
- uid_t uid;
- if (connman_dbus_get_connection_unix_user_sync(conn,
- dbus_message_get_sender(msg),
- &uid) < 0) {
- DBG("Can not get unix user id!");
- return __connman_error_permission_denied(msg);
- }
-
-#if !defined TIZEN_EXT
- if (!connman_service_is_user_allowed(service, uid)) {
- DBG("Not allow this user to remove this wifi service now!");
- return __connman_error_permission_denied(msg);
- }
-#endif
- }
-
if (!__connman_service_remove(service))
return __connman_error_not_supported(msg);
@@ -5953,7 +5862,7 @@ static void apply_relevant_default_downgrade(struct connman_service *service)
{
struct connman_service *def_service;
- def_service = __connman_service_get_default();
+ def_service = connman_service_get_default();
if (!def_service)
return;
@@ -5986,6 +5895,89 @@ static void switch_default_service(struct connman_service *default_service,
downgrade_state(downgrade_service);
}
+static struct _services_notify {
+ int id;
+ GHashTable *add;
+ GHashTable *remove;
+} *services_notify;
+
+
+static void service_append_added_foreach(gpointer data, gpointer user_data)
+{
+ struct connman_service *service = data;
+ DBusMessageIter *iter = user_data;
+
+ if (!service || !service->path) {
+ DBG("service %p or path is NULL", service);
+ return;
+ }
+
+ if (g_hash_table_lookup(services_notify->add, service->path)) {
+ DBG("new %s", service->path);
+
+ append_struct(service, iter);
+ g_hash_table_remove(services_notify->add, service->path);
+ } else {
+ DBG("changed %s", service->path);
+
+ append_struct_service(iter, NULL, service);
+ }
+}
+
+static void service_append_ordered(DBusMessageIter *iter, void *user_data)
+{
+ g_list_foreach(service_list, service_append_added_foreach, iter);
+}
+
+static void append_removed(gpointer key, gpointer value, gpointer user_data)
+{
+ char *objpath = key;
+ DBusMessageIter *iter = user_data;
+
+ DBG("removed %s", objpath);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
+}
+
+static void service_append_removed(DBusMessageIter *iter, void *user_data)
+{
+ g_hash_table_foreach(services_notify->remove, append_removed, iter);
+}
+
+static gboolean service_send_changed(gpointer data)
+{
+ DBusMessage *signal;
+
+ DBG("");
+
+ services_notify->id = 0;
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
+ if (!signal)
+ return FALSE;
+
+ __connman_dbus_append_objpath_dict_array(signal,
+ service_append_ordered, NULL);
+ __connman_dbus_append_objpath_array(signal,
+ service_append_removed, NULL);
+
+ dbus_connection_send(connection, signal, NULL);
+ dbus_message_unref(signal);
+
+ g_hash_table_remove_all(services_notify->remove);
+ g_hash_table_remove_all(services_notify->add);
+
+ return FALSE;
+}
+
+static void service_schedule_changed(void)
+{
+ if (services_notify->id != 0)
+ return;
+
+ services_notify->id = g_timeout_add(100, service_send_changed, NULL);
+}
+
static DBusMessage *move_service(DBusConnection *conn,
DBusMessage *msg, void *user_data,
bool before)
@@ -6092,6 +6084,8 @@ static DBusMessage *move_service(DBusConnection *conn,
__connman_connection_update_gateway();
+ service_schedule_changed();
+
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -6117,30 +6111,6 @@ static DBusMessage *reset_counters(DBusConnection *conn,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
-static DBusMessage *get_user_favorite(DBusConnection *conn,
- DBusMessage *msg, void *user_data)
-{
- DBusMessage *reply;
- uid_t uid = USER_NONE;
- dbus_bool_t user_favorite = false;
- struct connman_service *service = user_data;
-
- connman_dbus_get_connection_unix_user_sync(conn,
- dbus_message_get_sender(msg),
- &uid);
- if (uid == USER_ROOT)
- user_favorite = service->favorite;
- else if (uid != USER_NONE && uid == service->user.favorite_user) {
- DBG("The service is favorite to this user!");
- user_favorite = true;
- }
-
- reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
- dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
- &user_favorite, DBUS_TYPE_INVALID);
- return reply;
-}
-
#if defined TIZEN_MAINTAIN_ONLINE
static DBusMessage *downgrade_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
@@ -6154,94 +6124,6 @@ static DBusMessage *downgrade_service(DBusConnection *conn,
}
#endif
-static struct _services_notify {
- int id;
- GHashTable *add;
- GHashTable *remove;
-} *services_notify;
-
-static void service_append_added_foreach(gpointer data, gpointer user_data)
-{
- struct connman_service *service = data;
- DBusMessageIter *iter = user_data;
-
- if (!service || !service->path) {
-#if !defined TIZEN_EXT
- DBG("service %p or path is NULL", service);
-#endif
- return;
- }
-
- if (g_hash_table_lookup(services_notify->add, service->path)) {
-#if !defined TIZEN_EXT
- DBG("new %s", service->path);
-#endif
-
- append_struct(service, iter);
- g_hash_table_remove(services_notify->add, service->path);
- } else {
-#if !defined TIZEN_EXT
- DBG("changed %s", service->path);
-#endif
-
- append_struct_service(iter, NULL, service);
- }
-}
-
-static void service_append_ordered(DBusMessageIter *iter, void *user_data)
-{
- g_list_foreach(service_list, service_append_added_foreach, iter);
-}
-
-static void append_removed(gpointer key, gpointer value, gpointer user_data)
-{
- char *objpath = key;
- DBusMessageIter *iter = user_data;
-
- DBG("removed %s", objpath);
- dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
-}
-
-static void service_append_removed(DBusMessageIter *iter, void *user_data)
-{
- g_hash_table_foreach(services_notify->remove, append_removed, iter);
-}
-
-static gboolean service_send_changed(gpointer data)
-{
- DBusMessage *signal;
-
- DBG("");
-
- services_notify->id = 0;
-
- signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
- CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
- if (!signal)
- return FALSE;
-
- __connman_dbus_append_objpath_dict_array(signal,
- service_append_ordered, NULL);
- __connman_dbus_append_objpath_array(signal,
- service_append_removed, NULL);
-
- dbus_connection_send(connection, signal, NULL);
- dbus_message_unref(signal);
-
- g_hash_table_remove_all(services_notify->remove);
- g_hash_table_remove_all(services_notify->add);
-
- return FALSE;
-}
-
-static void service_schedule_changed(void)
-{
- if (services_notify->id != 0)
- return;
-
- services_notify->id = g_timeout_add(100, service_send_changed, NULL);
-}
-
static void service_schedule_added(struct connman_service *service)
{
DBG("service %p", service);
@@ -6303,9 +6185,6 @@ static const GDBusMethodTable service_methods[] = {
GDBUS_ARGS({ "service", "o" }), NULL,
move_after) },
{ GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
- { GDBUS_METHOD("GetUserFavorite",
- NULL, GDBUS_ARGS({ "value", "v" }),
- get_user_favorite) },
#if defined TIZEN_MAINTAIN_ONLINE
{ GDBUS_METHOD("Downgrade", NULL, NULL, downgrade_service) },
#endif
@@ -6449,11 +6328,6 @@ static void service_initialize(struct connman_service *service)
service->ignore = false;
- service->user.favorite_user = USER_NONE;
- service->user.current_user = USER_NONE;
-
- service->request_passphrase_input = false;
-
service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
service->order = 0;
@@ -6463,6 +6337,7 @@ static void service_initialize(struct connman_service *service)
service->provider = NULL;
service->wps = false;
+ service->wps_advertizing = false;
#if defined TIZEN_EXT
service->disconnection_requested = false;
service->storage_reload = false;
@@ -6709,40 +6584,6 @@ char *connman_service_get_interface(struct connman_service *service)
}
/**
- * __connman_service_is_user_allowed:
- * @type: service type
- * @uid: user id
- *
- * Check a user is allowed to operate a type of service
- */
-bool __connman_service_is_user_allowed(enum connman_service_type type,
- uid_t uid)
-{
- GList *list;
- uid_t owner_user = USER_NONE;
-
- for (list = service_list; list; list = list->next) {
- struct connman_service *service = list->data;
-
- if (service->type != type)
- continue;
-
- if (is_connected(service->state)) {
- owner_user = service->user.favorite_user;
- break;
- }
- }
-
- if (uid == USER_NONE ||
- (uid != USER_ROOT &&
- owner_user != USER_NONE &&
- owner_user != uid))
- return false;
-
- return true;
-}
-
-/**
* connman_service_get_network:
* @service: service structure
*
@@ -6908,9 +6749,6 @@ int __connman_service_set_favorite_delayed(struct connman_service *service,
service->favorite = favorite;
- if (!delay_ordering)
- __connman_service_get_order(service);
-
favorite_changed(service);
if (!delay_ordering) {
@@ -7032,6 +6870,14 @@ void __connman_service_set_search_domains(struct connman_service *service,
searchdomain_add_all(service);
}
+int __connman_service_set_mdns(struct connman_service *service,
+ bool enabled)
+{
+ service->mdns_config = enabled;
+
+ return set_mdns(service, enabled);
+}
+
static void report_error_cb(void *user_context, bool retry,
void *user_data)
{
@@ -7107,7 +6953,7 @@ static void request_input_cb(struct connman_service *service,
if (g_strcmp0(error,
"net.connman.Agent.Error.Canceled") == 0) {
- err = -EINVAL;
+ err = -ECONNABORTED;
if (service->hidden)
__connman_service_return_error(service,
@@ -7389,6 +7235,7 @@ static void single_connected_tech(struct connman_service *allowed)
if (service == allowed)
continue;
#endif
+
services = g_slist_prepend(services, service);
}
@@ -7465,7 +7312,7 @@ static int service_indicate_state(struct connman_service *service)
if (old_state == new_state)
return -EALREADY;
- def_service = __connman_service_get_default();
+ def_service = connman_service_get_default();
if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
result = service_update_preferred_order(def_service,
@@ -7536,7 +7383,7 @@ static int service_indicate_state(struct connman_service *service)
default_changed();
- def_service = __connman_service_get_default();
+ def_service = connman_service_get_default();
service_update_preferred_order(def_service, service, new_state);
@@ -7607,15 +7454,6 @@ static int service_indicate_state(struct connman_service *service)
reply_pending(service, ECONNABORTED);
- def_service = __connman_service_get_default();
- service->disconnect_reason = connman_network_get_disconnect_reason(service->network);
- service->assoc_status_code = connman_network_get_assoc_status_code(service->network);
-
- if (!__connman_notifier_is_connected() &&
- def_service &&
- def_service->provider)
- connman_provider_disconnect(def_service->provider);
-
default_changed();
__connman_wispr_stop(service);
@@ -7624,9 +7462,9 @@ static int service_indicate_state(struct connman_service *service)
#if defined TIZEN_EXT
/**
- * Skip the functions if there is any connected profiles
- * that use same interface
- */
+ * Skip the functions if there is any connected profiles
+ * that use same interface
+ */
if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
__connman_service_get_connected_count_of_iface(
service) <= 0) {
@@ -7653,15 +7491,14 @@ static int service_indicate_state(struct connman_service *service)
service->order = 5;
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
#endif
- if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
+ if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
connman_agent_report_error(service, service->path,
- error2string(service->error),
- report_error_cb,
- get_dbus_sender(service),
- NULL) == -EINPROGRESS)
- return 0;
+ error2string(service->error),
+ report_error_cb,
+ get_dbus_sender(service),
+ NULL);
+ }
service_complete(service);
-
break;
}
@@ -7689,20 +7526,6 @@ static int service_indicate_state(struct connman_service *service)
default_changed();
}
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
- service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
- (new_state == CONNMAN_SERVICE_STATE_READY ||
- new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
- if (service->user.favorite_user != service->user.current_user) {
- DBG("Now set service favorite user id from %d to %d",
- service->user.favorite_user, service->user.current_user);
-
- service->user.favorite_user = service->user.current_user;
-
- service_save(service);
- }
- }
-
return 0;
}
@@ -7835,7 +7658,7 @@ static void check_proxy_setup(struct connman_service *service)
return;
done:
- __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
}
#if defined TIZEN_EXT
@@ -7900,18 +7723,33 @@ static void service_rp_filter(struct connman_service *service,
connected_networks_count, original_rp_filter);
}
-static gboolean redo_wispr(gpointer user_data)
+static void redo_wispr(struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ service->online_timeout = 0;
+ connman_service_unref(service);
+
+ DBG("Retrying %s WISPr for %p %s",
+ __connman_ipconfig_type2string(type),
+ service, service->name);
+
+ __connman_wispr_start(service, type);
+}
+
+static gboolean redo_wispr_ipv4(gpointer user_data)
{
struct connman_service *service = user_data;
- int refcount = service->refcount - 1;
- connman_service_unref(service);
- if (refcount == 0) {
- DBG("Service %p already removed", service);
- return FALSE;
- }
+ redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV4);
- __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
+ return FALSE;
+}
+
+static gboolean redo_wispr_ipv6(gpointer user_data)
+{
+ struct connman_service *service = user_data;
+
+ redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV6);
return FALSE;
}
@@ -7932,40 +7770,42 @@ static gboolean redo_wispr_ipv4(gpointer user_data)
int __connman_service_online_check_failed(struct connman_service *service,
enum connman_ipconfig_type type)
{
- DBG("service %p type %d count %d", service, type,
- service->online_check_count);
+ GSourceFunc redo_func;
+ int *interval;
-#if defined TIZEN_MAINTAIN_ONLINE
- /* Retry IPv4 stuff also */
if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
- connman_warn("Online check failed for %p %s", service,
- service->name);
-
- g_timeout_add_seconds(1, redo_wispr_ipv4, service);
- return 0;
- }
-#else
- /* currently we only retry IPv6 stuff */
- if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
- service->online_check_count != 1) {
- connman_warn("Online check failed for %p %s", service,
- service->name);
- return 0;
+ interval = &service->online_check_interval_ipv4;
+ redo_func = redo_wispr_ipv4;
+ } else {
+ interval = &service->online_check_interval_ipv6;
+ redo_func = redo_wispr_ipv6;
}
-#endif
- service->online_check_count = 0;
+ DBG("service %p type %s interval %d", service,
+ __connman_ipconfig_type2string(type), *interval);
- /*
- * We set the timeout to 1 sec so that we have a chance to get
- * necessary IPv6 router advertisement messages that might have
- * DNS data etc.
+ service->online_timeout = g_timeout_add_seconds(*interval * *interval,
+ redo_func, connman_service_ref(service));
+
+ /* Increment the interval for the next time, set a maximum timeout of
+ * ONLINE_CHECK_MAX_INTERVAL * ONLINE_CHECK_MAX_INTERVAL seconds.
*/
- g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
+ if (*interval < ONLINE_CHECK_MAX_INTERVAL)
+ (*interval)++;
return EAGAIN;
}
+static void cancel_online_check(struct connman_service *service)
+{
+ if (service->online_timeout == 0)
+ return;
+
+ g_source_remove(service->online_timeout);
+ service->online_timeout = 0;
+ connman_service_unref(service);
+}
+
int __connman_service_ipconfig_indicate_state(struct connman_service *service,
enum connman_service_state new_state,
enum connman_ipconfig_type type)
@@ -8060,24 +7900,24 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
break;
}
#endif
- if (connman_setting_get_bool("EnableOnlineCheck")) {
+ if (connman_setting_get_bool("EnableOnlineCheck"))
if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
#if !defined TIZEN_EXT
check_proxy_setup(service);
#endif
#if defined TIZEN_MAINTAIN_ONLINE
-/* if (old_state == CONNMAN_SERVICE_STATE_ONLINE) */
- check_proxy_setup(service);
+/* if (old_state == CONNMAN_SERVICE_STATE_ONLINE) */
+ check_proxy_setup(service);
#endif
} else {
- service->online_check_count = 1;
- __connman_wispr_start(service, type);
+ __connman_service_wispr_start(service, type);
}
- } else
+ else
connman_info("Online check disabled. "
"Default service remains in READY state.");
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
service_rp_filter(service, true);
+ set_mdns(service, service->mdns_config);
break;
case CONNMAN_SERVICE_STATE_ONLINE:
break;
@@ -8097,8 +7937,10 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
break;
}
- if (is_connected(old_state) && !is_connected(new_state))
+ if (is_connected(old_state) && !is_connected(new_state)) {
nameserver_remove_all(service, type);
+ cancel_online_check(service);
+ }
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
service->state_ipv4 = new_state;
@@ -8290,11 +8132,7 @@ static int service_connect(struct connman_service *service)
if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
return -ENOKEY;
- if (service->request_passphrase_input) {
- DBG("Now try to connect other user's favorite service");
- service->request_passphrase_input = false;
- return -ENOKEY;
- } else if (!service->passphrase) {
+ if (!service->passphrase) {
if (!service->network)
return -EOPNOTSUPP;
@@ -8305,8 +8143,15 @@ static int service_connect(struct connman_service *service)
break;
case CONNMAN_SERVICE_SECURITY_8021X:
- if (!service->eap)
+ if (!service->eap) {
+ connman_warn("EAP type has not been found. "
+ "Most likely ConnMan is not able to "
+ "find a configuration for given "
+ "8021X network. "
+ "Check SSID or Name match with the "
+ "network name.");
return -EINVAL;
+ }
#if defined TIZEN_EXT
/*
@@ -8329,6 +8174,7 @@ static int service_connect(struct connman_service *service)
*/
if (g_str_equal(service->eap, "tls"))
break;
+
#endif
/*
* Return -ENOKEY if either identity or passphrase is
@@ -8445,6 +8291,7 @@ int __connman_service_connect(struct connman_service *service,
#if defined TIZEN_EXT
connect_reason_changed(service);
#endif
+
if (err >= 0)
return 0;
@@ -8487,7 +8334,6 @@ int __connman_service_connect(struct connman_service *service,
return err;
}
- reply_pending(service, -err);
}
return err;
@@ -8504,7 +8350,7 @@ int __connman_service_disconnect(struct connman_service *service)
connman_agent_cancel(service);
- reply_pending(service, ECONNABORTED);
+ __connman_stats_service_unregister(service);
if (service->network) {
err = __connman_network_disconnect(service->network);
@@ -8546,8 +8392,6 @@ int __connman_service_disconnect(struct connman_service *service)
}
#endif
- __connman_stats_service_unregister(service);
-
return err;
}
@@ -8594,7 +8438,7 @@ static struct connman_service *lookup_by_identifier(const char *identifier)
struct connman_service *connman_service_lookup_from_identifier(const char* identifier)
{
- return lookup_by_identifier(identifier);
+ return identifier ? lookup_by_identifier(identifier) : NULL;
}
struct provision_user_data {
@@ -8993,14 +8837,9 @@ struct connman_service *__connman_service_lookup_from_index(int index)
return NULL;
}
-struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
+const char *connman_service_get_identifier(struct connman_service *service)
{
- return lookup_by_identifier(identifier);
-}
-
-const char *__connman_service_get_ident(struct connman_service *service)
-{
- return service->identifier;
+ return service ? service->identifier : NULL;
}
const char *__connman_service_get_path(struct connman_service *service)
@@ -9013,65 +8852,9 @@ const char *__connman_service_get_name(struct connman_service *service)
return service->name;
}
-enum connman_service_state __connman_service_get_state(struct connman_service *service)
-{
- return service->state;
-}
-
-unsigned int __connman_service_get_order(struct connman_service *service)
+enum connman_service_state connman_service_get_state(struct connman_service *service)
{
- unsigned int order = 0;
-
- if (!service)
- return 0;
-
- service->order = 0;
-
- if (!service->favorite)
- return 0;
-
-#if defined TIZEN_EXT
- if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
- service->do_split_routing == FALSE)
- order = 10;
- else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
-#if defined TIZEN_MAINTAIN_ONLINE
- if (service->state != CONNMAN_SERVICE_STATE_ONLINE)
- service->order = 0;
- else if (service->order < 5)
- service->order = 5;
-#else
- if (service->order < 5)
- order = 5;
-#endif
- } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
- order = 4;
- else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
- order = 3;
- else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
- __connman_service_is_internet_profile(service) == TRUE)
- order = 1;
- else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
- __connman_service_is_tethering_profile(service) == TRUE)
- order = 0;
- else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
- order = 0;
- else
- order = 2;
-#else
- if (service == service_list->data)
- order = 1;
-
- if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
- !service->do_split_routing) {
- service->order = 10;
- order = 10;
- }
-#endif
- DBG("service %p name %s order %d split %d", service, service->name,
- order, service->do_split_routing);
-
- return order;
+ return service ? service->state : CONNMAN_SERVICE_STATE_UNKNOWN;
}
static enum connman_service_type convert_network_type(struct connman_network *network)
@@ -9142,6 +8925,21 @@ int check_passphrase_ext(struct connman_network *network,
}
#endif
+static void update_wps_values(struct connman_service *service,
+ struct connman_network *network)
+{
+ bool wps = connman_network_get_bool(network, "WiFi.WPS");
+ bool wps_advertising = connman_network_get_bool(network,
+ "WiFi.WPSAdvertising");
+
+ if (service->wps != wps ||
+ service->wps_advertizing != wps_advertising) {
+ service->wps = wps;
+ service->wps_advertizing = wps_advertising;
+ security_changed(service);
+ }
+}
+
static void update_from_network(struct connman_service *service,
struct connman_network *network)
{
@@ -9182,7 +8980,7 @@ static void update_from_network(struct connman_service *service,
service->security = convert_wifi_security(str);
if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
- service->wps = connman_network_get_bool(network, "WiFi.WPS");
+ update_wps_values(service, network);
if (service->strength > strength && service->network) {
connman_network_unref(service->network);
@@ -9209,7 +9007,7 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
struct connman_device *device;
const char *ident, *group;
char *name;
- unsigned int *auto_connect_types;
+ unsigned int *auto_connect_types, *favorite_types;
int i, index;
DBG("network %p", network);
@@ -9254,23 +9052,13 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
}
}
- switch (service->type) {
- case CONNMAN_SERVICE_TYPE_UNKNOWN:
- case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_BLUETOOTH:
- case CONNMAN_SERVICE_TYPE_GPS:
- case CONNMAN_SERVICE_TYPE_VPN:
- case CONNMAN_SERVICE_TYPE_GADGET:
- case CONNMAN_SERVICE_TYPE_WIFI:
- case CONNMAN_SERVICE_TYPE_CELLULAR:
- case CONNMAN_SERVICE_TYPE_P2P:
-#if defined TIZEN_EXT_WIFI_MESH
- case CONNMAN_SERVICE_TYPE_MESH:
-#endif
- break;
- case CONNMAN_SERVICE_TYPE_ETHERNET:
- service->favorite = true;
- break;
+ favorite_types = connman_setting_get_uint_list("DefaultFavoriteTechnologies");
+ service->favorite = false;
+ for (i = 0; favorite_types && favorite_types[i] != 0; i++) {
+ if (service->type == favorite_types[i]) {
+ service->favorite = true;
+ break;
+ }
}
service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
@@ -9292,7 +9080,8 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
if (service->favorite) {
device = connman_network_get_device(service->network);
- if (device && !connman_device_get_scanning(device)) {
+ if (device && !connman_device_get_scanning(device,
+ CONNMAN_SERVICE_TYPE_UNKNOWN)) {
switch (service->type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
@@ -9400,7 +9189,7 @@ void __connman_service_update_from_network(struct connman_network *network)
}
if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
- service->wps = connman_network_get_bool(network, "WiFi.WPS");
+ update_wps_values(service, network);
strength = connman_network_get_strength(service->network);
if (strength == service->strength)
@@ -9481,6 +9270,7 @@ __connman_service_create_from_provider(struct connman_provider *provider)
return NULL;
service->type = CONNMAN_SERVICE_TYPE_VPN;
+ service->order = service->do_split_routing ? 0 : 10;
service->provider = connman_provider_ref(provider);
service->autoconnect = false;
service->favorite = true;
@@ -9644,14 +9434,14 @@ void __connman_service_cleanup(void)
{
DBG("");
- if (vpn_autoconnect_timeout) {
- g_source_remove(vpn_autoconnect_timeout);
- vpn_autoconnect_timeout = 0;
+ if (vpn_autoconnect_id) {
+ g_source_remove(vpn_autoconnect_id);
+ vpn_autoconnect_id = 0;
}
- if (autoconnect_timeout != 0) {
- g_source_remove(autoconnect_timeout);
- autoconnect_timeout = 0;
+ if (autoconnect_id != 0) {
+ g_source_remove(autoconnect_id);
+ autoconnect_id = 0;
}
connman_agent_driver_unregister(&agent_driver);
diff --git a/src/session.c b/src/session.c
index 26cbf878..808931a8 100644
--- a/src/session.c
+++ b/src/session.c
@@ -28,8 +28,6 @@
#include <gdbus.h>
-#include <connman/session.h>
-
#include "connman.h"
static DBusConnection *connection;
@@ -65,7 +63,9 @@ struct connman_session {
struct firewall_context *fw;
uint32_t mark;
int index;
+ char *addr;
char *gateway;
+ unsigned char prefixlen;
bool policy_routing;
bool snat_enabled;
};
@@ -79,6 +79,7 @@ struct fw_snat {
GSList *sessions;
int id;
int index;
+ char *addr;
struct firewall_context *fw;
};
@@ -203,7 +204,7 @@ static char *service2bearer(enum connman_service_type type)
return "";
}
-static struct fw_snat *fw_snat_lookup(int index)
+static struct fw_snat *fw_snat_lookup(int index, const char *addr)
{
struct fw_snat *fw_snat;
GSList *list;
@@ -211,8 +212,11 @@ static struct fw_snat *fw_snat_lookup(int index)
for (list = fw_snat_list; list; list = list->next) {
fw_snat = list->data;
- if (fw_snat->index == index)
+ if (fw_snat->index == index) {
+ if (g_strcmp0(addr, fw_snat->addr) != 0)
+ continue;
return fw_snat;
+ }
}
return NULL;
}
@@ -227,6 +231,7 @@ static int fw_snat_create(struct connman_session *session,
fw_snat->fw = __connman_firewall_create();
fw_snat->index = index;
+ fw_snat->addr = g_strdup(addr);
fw_snat->id = __connman_firewall_enable_snat(fw_snat->fw,
index, ifname, addr);
@@ -241,6 +246,7 @@ static int fw_snat_create(struct connman_session *session,
return 0;
err:
__connman_firewall_destroy(fw_snat->fw);
+ g_free(fw_snat->addr);
g_free(fw_snat);
return err;
}
@@ -353,13 +359,17 @@ static void del_default_route(struct connman_session *session)
if (!session->gateway)
return;
- DBG("index %d routing table %d default gateway %s",
- session->index, session->mark, session->gateway);
+ DBG("index %d routing table %d default gateway %s/%u",
+ session->index, session->mark, session->gateway, session->prefixlen);
+
+ __connman_inet_del_subnet_from_table(session->mark,
+ session->index, session->gateway, session->prefixlen);
__connman_inet_del_default_from_table(session->mark,
session->index, session->gateway);
g_free(session->gateway);
session->gateway = NULL;
+ session->prefixlen = 0;
session->index = -1;
}
@@ -379,13 +389,20 @@ static void add_default_route(struct connman_session *session)
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);
+ session->prefixlen = __connman_ipconfig_get_prefixlen(ipconfig);
+
+ DBG("index %d routing table %d default gateway %s/%u",
+ session->index, session->mark, session->gateway, session->prefixlen);
err = __connman_inet_add_default_to_table(session->mark,
session->index, session->gateway);
if (err < 0)
DBG("session %p %s", session, strerror(-err));
+
+ err = __connman_inet_add_subnet_to_table(session->mark,
+ session->index, session->gateway, session->prefixlen);
+ if (err < 0)
+ DBG("session add subnet route %p %s", session, strerror(-err));
}
static void del_nat_rules(struct connman_session *session)
@@ -396,7 +413,7 @@ static void del_nat_rules(struct connman_session *session)
return;
session->snat_enabled = false;
- fw_snat = fw_snat_lookup(session->index);
+ fw_snat = fw_snat_lookup(session->index, session->addr);
if (!fw_snat)
return;
@@ -423,8 +440,11 @@ static void add_nat_rules(struct connman_session *session)
if (!addr)
return;
+ g_free(session->addr);
+ session->addr = g_strdup(addr);
+
session->snat_enabled = true;
- fw_snat = fw_snat_lookup(index);
+ fw_snat = fw_snat_lookup(index, session->addr);
if (fw_snat) {
fw_snat_ref(session, fw_snat);
return;
@@ -496,6 +516,9 @@ static void free_session(struct connman_session *session)
if (session->notify_watch > 0)
g_dbus_remove_watch(connection, session->notify_watch);
+ g_dbus_unregister_interface(connection, session->session_path,
+ CONNMAN_SESSION_INTERFACE);
+
destroy_policy_config(session);
g_slist_free(session->info->config.allowed_bearers);
g_free(session->info->config.allowed_interface);
@@ -505,6 +528,7 @@ static void free_session(struct connman_session *session)
g_free(session->info);
g_free(session->info_last);
g_free(session->gateway);
+ g_free(session->addr);
g_free(session);
}
@@ -551,6 +575,7 @@ struct creation_data {
GSList *allowed_bearers;
char *allowed_interface;
bool source_ip_rule;
+ char *context_identifier;
};
static void cleanup_creation_data(struct creation_data *creation_data)
@@ -560,6 +585,8 @@ static void cleanup_creation_data(struct creation_data *creation_data)
if (creation_data->pending)
dbus_message_unref(creation_data->pending);
+ if (creation_data->context_identifier)
+ g_free(creation_data->context_identifier);
g_slist_free(creation_data->allowed_bearers);
g_free(creation_data->allowed_interface);
@@ -930,6 +957,17 @@ static void append_notify(DBusMessageIter *dict,
}
if (session->append_all ||
+ info->config.context_identifier != info_last->config.context_identifier) {
+ char *ifname = info->config.context_identifier;
+ if (!ifname)
+ ifname = "";
+ connman_dbus_dict_append_basic(dict, "ContextIdentifier",
+ DBUS_TYPE_STRING,
+ &ifname);
+ info_last->config.context_identifier = info->config.context_identifier;
+ }
+
+ 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)
@@ -1375,7 +1413,7 @@ static int session_policy_config_cb(struct connman_session *session,
connman_error("Failed to register %s", session->session_path);
g_hash_table_remove(session_hash, session->session_path);
err = -EINVAL;
- goto err;
+ goto err_notify;
}
reply = g_dbus_create_reply(creation_data->pending,
@@ -1400,11 +1438,13 @@ static int session_policy_config_cb(struct connman_session *session,
return 0;
err:
+ cleanup_session(session);
+
+err_notify:
reply = __connman_error_failed(creation_data->pending, -err);
g_dbus_send_message(connection, reply);
creation_data->pending = NULL;
- cleanup_session(session);
cleanup_creation_data(creation_data);
return err;
@@ -1477,6 +1517,9 @@ int __connman_session_create(DBusMessage *msg)
connman_session_parse_connection_type(val);
user_connection_type = true;
+ } else if (g_str_equal(key, "ContextIdentifier")) {
+ dbus_message_iter_get_basic(&value, &val);
+ creation_data->context_identifier = g_strdup(val);
} else if (g_str_equal(key, "AllowedInterface")) {
dbus_message_iter_get_basic(&value, &val);
creation_data->allowed_interface = g_strdup(val);
@@ -1675,7 +1718,7 @@ static void update_session_state(struct connman_session *session)
enum connman_session_state state = CONNMAN_SESSION_STATE_DISCONNECTED;
if (session->service) {
- service_state = __connman_service_get_state(session->service);
+ service_state = connman_service_get_state(session->service);
state = service_to_session_state(service_state);
session->info->state = state;
}
@@ -1770,7 +1813,7 @@ static void session_activate(struct connman_session *session)
while (g_hash_table_iter_next(&iter, &key, &value)) {
struct connman_service_info *info = value;
- state = __connman_service_get_state(info->service);
+ state = connman_service_get_state(info->service);
if (is_session_connected(session, state))
service_list = g_slist_prepend(service_list,
@@ -1799,7 +1842,7 @@ static void session_activate(struct connman_session *session)
struct connman_service_info *info = value;
enum connman_service_state state;
- state = __connman_service_get_state(info->service);
+ state = connman_service_get_state(info->service);
if (is_session_connected(session, state) &&
session_match_service(session, info->service)) {
@@ -1961,7 +2004,7 @@ static void ipconfig_changed(struct connman_service *service,
}
}
-static struct connman_notifier session_notifier = {
+static const struct connman_notifier session_notifier = {
.name = "session",
.service_state_changed = service_state_changed,
.ipconfig_changed = ipconfig_changed,
diff --git a/src/shared/arp.c b/src/shared/arp.c
new file mode 100644
index 00000000..6cd611f2
--- /dev/null
+++ b/src/shared/arp.c
@@ -0,0 +1,126 @@
+/*
+ *
+ * Connection Manager
+ *
+ * based on IPv4 Local Link library with GLib integration,
+ * Copyright (C) 2009-2010 Aldebaran Robotics. All rights reserved.
+ *
+ * Copyright (C) 2018 Commend International. 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.
+ *
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <netinet/if_ether.h>
+#include <net/if_arp.h>
+
+#include <arpa/inet.h>
+
+#include "src/shared/arp.h"
+#include "src/connman.h"
+
+int arp_send_packet(uint8_t* source_eth, uint32_t source_ip,
+ uint32_t target_ip, int ifindex)
+{
+ struct sockaddr_ll dest;
+ struct ether_arp p;
+ uint32_t ip_source;
+ uint32_t ip_target;
+ int fd, n;
+
+ fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return -errno;
+
+ memset(&dest, 0, sizeof(dest));
+ memset(&p, 0, sizeof(p));
+
+ dest.sll_family = AF_PACKET;
+ dest.sll_protocol = htons(ETH_P_ARP);
+ dest.sll_ifindex = ifindex;
+ dest.sll_halen = ETH_ALEN;
+ memset(dest.sll_addr, 0xFF, ETH_ALEN);
+ if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
+
+ ip_source = htonl(source_ip);
+ ip_target = htonl(target_ip);
+ p.arp_hrd = htons(ARPHRD_ETHER);
+ p.arp_pro = htons(ETHERTYPE_IP);
+ p.arp_hln = ETH_ALEN;
+ p.arp_pln = 4;
+ p.arp_op = htons(ARPOP_REQUEST);
+
+ memcpy(&p.arp_sha, source_eth, ETH_ALEN);
+ memcpy(&p.arp_spa, &ip_source, sizeof(p.arp_spa));
+ memcpy(&p.arp_tpa, &ip_target, sizeof(p.arp_tpa));
+
+ n = sendto(fd, &p, sizeof(p), 0,
+ (struct sockaddr*) &dest, sizeof(dest));
+ if (n < 0)
+ n = -errno;
+
+ close(fd);
+
+ return n;
+}
+
+int arp_socket(int ifindex)
+{
+ int fd;
+ struct sockaddr_ll sock;
+
+ fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return fd;
+
+ memset(&sock, 0, sizeof(sock));
+
+ sock.sll_family = AF_PACKET;
+ sock.sll_protocol = htons(ETH_P_ARP);
+ sock.sll_ifindex = ifindex;
+
+ if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) != 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
+
+ return fd;
+}
+
+/**
+ * Return a random link local IP (in host byte order)
+ */
+uint32_t arp_random_ip(void)
+{
+ unsigned tmp;
+
+ do {
+ uint64_t rand;
+ __connman_util_get_random(&rand);
+ tmp = rand;
+ tmp = tmp & IN_CLASSB_HOST;
+ } while (tmp > (IN_CLASSB_HOST - 0x0200));
+
+ return (LINKLOCAL_ADDR + 0x0100) + tmp;
+}
diff --git a/src/shared/arp.h b/src/shared/arp.h
new file mode 100755
index 00000000..03e2168c
--- /dev/null
+++ b/src/shared/arp.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Connection Manager
+ *
+ * based on IPv4 Local Link library with GLib integration,
+ * Copyright (C) 2009-2010 Aldebaran Robotics. All rights reserved.
+ *
+ * Copyright (C) 2018 Commend International. 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.
+ *
+ */
+
+#ifndef SHARED_ARP_H
+#define SHARED_ARP_H
+
+#include <stdint.h>
+
+/* IPv4 Link-Local (RFC 3927), IPv4 Address Conflict Detection (RFC 5227) */
+#define PROBE_WAIT 1
+#define PROBE_NUM 3
+#define PROBE_MIN 1
+#define PROBE_MAX 2
+#define ANNOUNCE_WAIT 2
+#define ANNOUNCE_NUM 2
+#define ANNOUNCE_INTERVAL 2
+#define MAX_CONFLICTS 10
+#define RATE_LIMIT_INTERVAL 60
+#define DEFEND_INTERVAL 10
+
+/* 169.254.0.0 */
+#define LINKLOCAL_ADDR 0xa9fe0000
+
+int arp_send_packet(uint8_t* source_eth, uint32_t source_ip,
+ uint32_t target_ip, int ifindex);
+int arp_socket(int ifindex);
+
+uint32_t arp_random_ip(void);
+
+#endif
diff --git a/src/stats.c b/src/stats.c
index 663bc382..6f7ce208 100755
--- a/src/stats.c
+++ b/src/stats.c
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <errno.h>
#include <sys/mman.h>
#include <sys/types.h>
@@ -678,7 +677,7 @@ int __connman_stats_service_register(struct connman_service *service)
DBG("service %p", service);
dir = g_strdup_printf("%s/%s", STORAGEDIR,
- __connman_service_get_ident(service));
+ connman_service_get_identifier(service));
/* If the dir doesn't exist, create it */
if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) {
@@ -707,9 +706,9 @@ int __connman_stats_service_register(struct connman_service *service)
}
name = g_strdup_printf("%s/%s/data", STORAGEDIR,
- __connman_service_get_ident(service));
+ connman_service_get_identifier(service));
file->history_name = g_strdup_printf("%s/%s/history", STORAGEDIR,
- __connman_service_get_ident(service));
+ connman_service_get_identifier(service));
/* TODO: Use a global config file instead of hard coded value. */
file->account_period_offset = 1;
diff --git a/src/storage.c b/src/storage.c
index 50c8e955..6ca600b2 100755
--- a/src/storage.c
+++ b/src/storage.c
@@ -23,11 +23,11 @@
#include <config.h>
#endif
-#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
+#include <stdio.h>
#include <connman/storage.h>
diff --git a/src/technology.c b/src/technology.c
index 2f14d57d..782ce15c 100644
--- a/src/technology.c
+++ b/src/technology.c
@@ -80,7 +80,6 @@ struct connman_technology {
*/
char *tethering_ident;
char *tethering_passphrase;
- bool tethering_hidden;
bool enable_persistent; /* Save the tech state */
@@ -122,7 +121,7 @@ static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
struct connman_rfkill *rfkill = value;
enum connman_service_type type = GPOINTER_TO_INT(user_data);
- /* Calling _technology_rfkill_add will update the tech. */
+ /* Calling _technology_add_rfkill will update the tech. */
if (rfkill->type == type)
__connman_technology_add_rfkill(rfkill->index, type,
rfkill->softblock, rfkill->hardblock);
@@ -206,9 +205,6 @@ static void technology_save(struct connman_technology *technology)
g_key_file_set_boolean(keyfile, identifier, "Tethering",
technology->tethering_persistent);
- g_key_file_set_boolean(keyfile, identifier, "Hidden",
- technology->tethering_hidden);
-
if (technology->tethering_ident)
g_key_file_set_string(keyfile, identifier,
"Tethering.Identifier",
@@ -225,8 +221,6 @@ done:
__connman_storage_save_global(keyfile);
g_key_file_free(keyfile);
-
- return;
}
static void tethering_changed(struct connman_technology *technology)
@@ -282,7 +276,8 @@ static int set_tethering(struct connman_technology *technology,
if (!bridge)
return -EOPNOTSUPP;
- if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && (!ident))
+ if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
+ (!ident || !passphrase))
return -EINVAL;
for (tech_drivers = technology->driver_list; tech_drivers;
@@ -375,6 +370,15 @@ static struct connman_technology *technology_find(enum connman_service_type type
return NULL;
}
+enum connman_service_type connman_technology_get_type
+ (struct connman_technology *technology)
+{
+ if (!technology)
+ return CONNMAN_SERVICE_TYPE_UNKNOWN;
+
+ return technology->type;
+}
+
bool connman_technology_get_wifi_tethering(const char **ssid,
const char **psk)
{
@@ -473,8 +477,6 @@ done:
g_free(identifier);
g_key_file_free(keyfile);
-
- return;
}
bool __connman_technology_get_offlinemode(void)
@@ -512,8 +514,6 @@ static void connman_technology_save_offlinemode(void)
}
g_key_file_free(keyfile);
-
- return;
}
static bool connman_technology_load_offlinemode(void)
@@ -584,11 +584,6 @@ static void append_properties(DBusMessageIter *iter,
DBUS_TYPE_STRING,
&technology->tethering_passphrase);
- val = technology->tethering_hidden;
- connman_dbus_dict_append_basic(&dict, "Hidden",
- DBUS_TYPE_BOOLEAN,
- &val);
-
connman_dbus_dict_close(iter, &dict);
}
@@ -663,7 +658,7 @@ static gboolean technology_pending_reply(gpointer user_data)
struct connman_technology *technology = user_data;
DBusMessage *reply;
- /* Power request timedout, send ETIMEDOUT. */
+ /* Power request timed out, send ETIMEDOUT. */
if (technology->pending_reply) {
reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
if (reply)
@@ -839,6 +834,8 @@ static int technology_disable(struct connman_technology *technology)
if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
technology->enable_persistent = false;
+ __connman_device_stop_scan(CONNMAN_SERVICE_TYPE_P2P);
+ __connman_peer_disconnect_all();
return technology_disabled(technology);
} else if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
struct connman_technology *p2p;
@@ -977,21 +974,6 @@ static DBusMessage *set_property(DBusConnection *conn,
DBG("property %s", name);
- if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && technology->connected) {
- uid_t uid;
- if (connman_dbus_get_connection_unix_user_sync(conn,
- dbus_message_get_sender(msg),
- &uid) < 0) {
- DBG("Can not get unix user id!");
- return __connman_error_permission_denied(msg);
- }
-
- if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
- DBG("Not allow this user to operate wifi technology now!");
- return __connman_error_permission_denied(msg);
- }
- }
-
if (g_str_equal(name, "Tethering")) {
dbus_bool_t tethering;
int err;
@@ -1068,25 +1050,6 @@ static DBusMessage *set_property(DBusConnection *conn,
DBUS_TYPE_STRING,
&technology->tethering_passphrase);
}
- } else if (g_str_equal(name, "Hidden")) {
- dbus_bool_t hidden;
-
- if (type != DBUS_TYPE_BOOLEAN)
- return __connman_error_invalid_arguments(msg);
-
- dbus_message_iter_get_basic(&value, &hidden);
-
- if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
- return __connman_error_not_supported(msg);
-
- technology->tethering_hidden = hidden;
- technology_save(technology);
-
- connman_dbus_property_changed_basic(technology->path,
- CONNMAN_TECHNOLOGY_INTERFACE,
- "Hidden",
- DBUS_TYPE_BOOLEAN,
- &hidden);
} else if (g_str_equal(name, "Powered")) {
dbus_bool_t enable;
@@ -1191,10 +1154,7 @@ void __connman_technology_scan_stopped(struct connman_device *device,
if (device == other_device)
continue;
- if (__connman_device_get_service_type(other_device) != type)
- continue;
-
- if (connman_device_get_scanning(other_device))
+ if (connman_device_get_scanning(other_device, type))
count += 1;
}
@@ -1280,12 +1240,11 @@ static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
g_slist_prepend(technology->scan_pending, msg);
#endif
- err = __connman_device_request_scan(technology->type);
-#if defined TIZEN_EXT
+ err = __connman_device_request_scan_full(technology->type);
if (err < 0)
+#if defined TIZEN_EXT
return __connman_error_failed(msg, -err);
#else
- if (err < 0)
reply_scan_pending(technology, err);
#endif
@@ -1463,7 +1422,8 @@ static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void
for (list = technology->device_list; list; list = list->next) {
struct connman_device *device = list->data;
- scanning = connman_device_get_scanning(device);
+ scanning = connman_device_get_scanning(device,
+ connman_device_get_type(device));
if(scanning)
break;
}
@@ -2012,16 +1972,6 @@ static const GDBusMethodTable technology_methods[] = {
static const GDBusSignalTable technology_signals[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
- { GDBUS_SIGNAL("DhcpConnected",
- GDBUS_ARGS({ "aptype", "s" },
- { "ipaddr", "s" },
- { "macaddr", "s" },
- { "hostname", "s" })) },
- { GDBUS_SIGNAL("DhcpLeaseDeleted",
- GDBUS_ARGS({ "aptype", "s" },
- { "ipaddr", "s" },
- { "macaddr", "s" },
- { "hostname", "s" })) },
{ },
};
@@ -2148,7 +2098,6 @@ static struct connman_technology *technology_get(enum connman_service_type type)
technology->refcount = 1;
technology->type = type;
- technology->tethering_hidden = FALSE;
technology->path = g_strdup_printf("%s/technology/%s",
CONNMAN_PATH, str);
@@ -2428,7 +2377,7 @@ int __connman_technology_add_device(struct connman_device *device)
int err = __connman_device_enable(device);
/*
* connman_technology_add_device() calls __connman_device_enable()
- * but since the device is already enabled, the calls does not
+ * but since the device is already enabled, the call does not
* propagate through to connman_technology_enabled via
* connman_device_set_powered.
*/
@@ -2484,6 +2433,7 @@ int __connman_technology_enabled(enum connman_service_type type)
DBG("technology %p type %s rfkill %d enabled %d", technology,
get_name(type), technology->rfkill_driven,
technology->enabled);
+
#if !defined TIZEN_EXT
if (technology->rfkill_driven) {
if (technology->tethering_persistent)
@@ -2503,9 +2453,11 @@ int __connman_technology_disabled(enum connman_service_type type)
technology = technology_find(type);
if (!technology)
return -ENXIO;
+
#if !defined TIZEN_EXT
if (technology->rfkill_driven)
return 0;
+
#endif
for (list = technology->device_list; list; list = list->next) {
struct connman_device *device = list->data;
@@ -2533,7 +2485,7 @@ int __connman_technology_set_offlinemode(bool offlinemode)
* resuming offlinemode from last saved profile. We need that
* information in rfkill_update, otherwise it falls back on the
* technology's persistent state. Hence we set the offline mode here
- * but save it & call the notifier only if its successful.
+ * but save it & call the notifier only if it is successful.
*/
global_offlinemode = offlinemode;
@@ -2716,6 +2668,7 @@ done:
softblock, hardblock, true))
return 0;
#endif
+
if (global_offlinemode)
return 0;
diff --git a/src/tethering.c b/src/tethering.c
index 891ee51f..e04756ff 100755
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -31,11 +31,11 @@
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
-#include <linux/sockios.h>
#include <string.h>
#include <fcntl.h>
-#include <linux/if_tun.h>
#include <netinet/in.h>
+#include <linux/sockios.h>
+#include <linux/if_tun.h>
#include <linux/if_bridge.h>
#include "connman.h"
@@ -52,9 +52,6 @@
#define DEFAULT_MTU 1500
-#define CONNMAN_STATION_STR_INFO_LEN 64
-#define CONNMAN_STATION_MAC_INFO_LEN 32
-
static char *private_network_primary_dns = NULL;
static char *private_network_secondary_dns = NULL;
@@ -63,7 +60,13 @@ static GDHCPServer *tethering_dhcp_server = NULL;
static struct connman_ippool *dhcp_ippool = NULL;
static DBusConnection *connection;
static GHashTable *pn_hash;
-static GHashTable *sta_hash;
+
+static GHashTable *clients_table;
+
+struct _clients_notify {
+ int id;
+ GHashTable *remove;
+} *clients_notify;
struct connman_private_network {
char *owner;
@@ -80,164 +83,6 @@ struct connman_private_network {
char *secondary_dns;
};
-struct connman_station_info {
- bool is_connected;
- char *path;
- char *type;
- char ip[CONNMAN_STATION_STR_INFO_LEN];
- char mac[CONNMAN_STATION_MAC_INFO_LEN];
- char hostname[CONNMAN_STATION_STR_INFO_LEN];
-};
-
-static void emit_station_signal(char *action_str,
- const struct connman_station_info *station_info)
-{
- char *ip, *mac, *hostname;
-
- if (station_info->path == NULL || station_info->type == NULL
- || station_info->ip == NULL || station_info->mac == NULL
- || station_info->hostname == NULL)
- return;
-
- ip = g_strdup(station_info->ip);
- mac = g_strdup(station_info->mac);
- hostname = g_strdup(station_info->hostname);
-
- g_dbus_emit_signal(connection, station_info->path,
- CONNMAN_TECHNOLOGY_INTERFACE, action_str,
- DBUS_TYPE_STRING, &station_info->type,
- DBUS_TYPE_STRING, &ip,
- DBUS_TYPE_STRING, &mac,
- DBUS_TYPE_STRING, &hostname,
- DBUS_TYPE_INVALID);
-
- g_free(ip);
- g_free(mac);
- g_free(hostname);
-}
-static void destroy_station(gpointer key, gpointer value, gpointer user_data)
-{
- struct connman_station_info *station_info;
-
- __sync_synchronize();
-
- station_info = value;
-
- if (station_info->is_connected) {
- station_info->is_connected = FALSE;
- emit_station_signal("DhcpLeaseDeleted", station_info);
- }
-
- g_free(station_info->path);
- g_free(station_info->type);
- g_free(station_info);
-}
-
-static void save_dhcp_ack_lease_info(char *hostname,
- unsigned char *mac, unsigned int nip)
-{
- char *lower_mac;
- const char *ip;
- char sta_mac[CONNMAN_STATION_MAC_INFO_LEN];
- struct connman_station_info *info_found;
- struct in_addr addr;
- int str_len;
-
- __sync_synchronize();
-
- snprintf(sta_mac, CONNMAN_STATION_MAC_INFO_LEN,
- "%02x:%02x:%02x:%02x:%02x:%02x",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- lower_mac = g_ascii_strdown(sta_mac, -1);
-
- info_found = g_hash_table_lookup(sta_hash, lower_mac);
- if (info_found == NULL) {
- g_free(lower_mac);
- return;
- }
-
- /* get the ip */
- addr.s_addr = nip;
- ip = inet_ntoa(addr);
- str_len = strlen(ip) + 1;
- if (str_len > CONNMAN_STATION_STR_INFO_LEN)
- str_len = CONNMAN_STATION_STR_INFO_LEN - 1;
- memcpy(info_found->ip, ip, str_len);
-
- /* get hostname */
- str_len = strlen(hostname) + 1;
- if (str_len > CONNMAN_STATION_STR_INFO_LEN)
- str_len = CONNMAN_STATION_STR_INFO_LEN - 1;
- memcpy(info_found->hostname, hostname, str_len);
-
- /* emit a signal */
- info_found->is_connected = TRUE;
- emit_station_signal("DhcpConnected", info_found);
- g_free(lower_mac);
-}
-
-int connman_technology_tethering_add_station(enum connman_service_type type,
- const char *mac)
-{
- const char *str_type;
- char *lower_mac;
- char *path;
- struct connman_station_info *station_info;
-
- __sync_synchronize();
-
- DBG("type %d", type);
-
- str_type = __connman_service_type2string(type);
- if (str_type == NULL)
- return 0;
-
- path = g_strdup_printf("%s/technology/%s", CONNMAN_PATH, str_type);
-
- station_info = g_try_new0(struct connman_station_info, 1);
- if (station_info == NULL)
- return -ENOMEM;
-
- lower_mac = g_ascii_strdown(mac, -1);
-
- memcpy(station_info->mac, lower_mac, strlen(lower_mac) + 1);
- station_info->path = path;
- station_info->type = g_strdup(str_type);
-
- g_hash_table_insert(sta_hash, station_info->mac, station_info);
-
- g_free(lower_mac);
- return 0;
-}
-
-int connman_technology_tethering_remove_station(const char *mac)
-{
- char *lower_mac;
- struct connman_station_info *info_found;
-
- __sync_synchronize();
-
- lower_mac = g_ascii_strdown(mac, -1);
-
- info_found = g_hash_table_lookup(sta_hash, lower_mac);
- if (info_found == NULL) {
- g_free(lower_mac);
- return -EACCES;
- }
-
- if (info_found->is_connected) {
- info_found->is_connected = FALSE;
- emit_station_signal("DhcpLeaseDeleted", info_found);
- }
- g_free(lower_mac);
- g_hash_table_remove(sta_hash, info_found->mac);
- g_free(info_found->path);
- g_free(info_found->type);
- g_free(info_found);
-
- return 0;
-}
-
const char *__connman_tethering_get_bridge(void)
{
int sk, err;
@@ -323,9 +168,6 @@ static GDHCPServer *dhcp_server_start(const char *bridge,
g_dhcp_server_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);
g_dhcp_server_set_ip_range(dhcp_server, start_ip, end_ip);
- g_dhcp_server_set_save_ack_lease(dhcp_server,
- save_dhcp_ack_lease_info, NULL);
-
g_dhcp_server_start(dhcp_server);
return dhcp_server;
@@ -346,6 +188,18 @@ static void tethering_restart(struct connman_ippool *pool, void *user_data)
__connman_tethering_set_enabled();
}
+static void unregister_client(gpointer key,
+ gpointer value, gpointer user_data)
+{
+ const char *addr = key;
+ __connman_tethering_client_unregister(addr);
+}
+
+static void unregister_all_clients(void)
+{
+ g_hash_table_foreach(clients_table, unregister_client, NULL);
+}
+
int __connman_tethering_set_enabled(void)
{
int index;
@@ -390,7 +244,8 @@ int __connman_tethering_set_enabled(void)
connman_ipaddress_calc_netmask_len(subnet_mask),
broadcast);
if (err < 0 && err != -EALREADY) {
- __connman_ippool_unref(dhcp_ippool);
+ __connman_ippool_free(dhcp_ippool);
+ dhcp_ippool = NULL;
__connman_bridge_remove(BRIDGE_NAME);
__sync_fetch_and_sub(&tethering_enabled, 1);
return -EADDRNOTAVAIL;
@@ -426,7 +281,8 @@ int __connman_tethering_set_enabled(void)
24 * 3600, dns);
if (!tethering_dhcp_server) {
__connman_bridge_disable(BRIDGE_NAME);
- __connman_ippool_unref(dhcp_ippool);
+ __connman_ippool_free(dhcp_ippool);
+ dhcp_ippool = NULL;
__connman_bridge_remove(BRIDGE_NAME);
__sync_fetch_and_sub(&tethering_enabled, 1);
return -EOPNOTSUPP;
@@ -438,7 +294,8 @@ int __connman_tethering_set_enabled(void)
connman_error("Cannot enable NAT %d/%s", err, strerror(-err));
dhcp_server_stop(tethering_dhcp_server);
__connman_bridge_disable(BRIDGE_NAME);
- __connman_ippool_unref(dhcp_ippool);
+ __connman_ippool_free(dhcp_ippool);
+ dhcp_ippool = NULL;
__connman_bridge_remove(BRIDGE_NAME);
__sync_fetch_and_sub(&tethering_enabled, 1);
return -EOPNOTSUPP;
@@ -463,6 +320,8 @@ void __connman_tethering_set_disabled(void)
if (__sync_fetch_and_sub(&tethering_enabled, 1) != 1)
return;
+ unregister_all_clients();
+
__connman_ipv6pd_cleanup();
index = connman_inet_ifindex(BRIDGE_NAME);
@@ -476,7 +335,8 @@ void __connman_tethering_set_disabled(void)
__connman_bridge_disable(BRIDGE_NAME);
- __connman_ippool_unref(dhcp_ippool);
+ __connman_ippool_free(dhcp_ippool);
+ dhcp_ippool = NULL;
__connman_bridge_remove(BRIDGE_NAME);
@@ -488,6 +348,21 @@ void __connman_tethering_set_disabled(void)
DBG("tethering stopped");
}
+static void append_client(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ const char *addr = key;
+ DBusMessageIter *array = user_data;
+
+ dbus_message_iter_append_basic(array, DBUS_TYPE_STRING,
+ &addr);
+}
+
+void __connman_tethering_list_clients(DBusMessageIter *array)
+{
+ g_hash_table_foreach(clients_table, append_client, array);
+}
+
static void setup_tun_interface(unsigned int flags, unsigned change,
void *data)
{
@@ -564,7 +439,7 @@ static void remove_private_network(gpointer user_data)
__connman_nat_disable(BRIDGE_NAME);
connman_rtnl_remove_watch(pn->iface_watch);
- __connman_ippool_unref(pn->pool);
+ __connman_ippool_free(pn->pool);
if (pn->watch > 0) {
g_dbus_remove_watch(connection, pn->watch);
@@ -601,6 +476,70 @@ static void ippool_disconnect(struct connman_ippool *pool, void *user_data)
g_hash_table_remove(pn_hash, pn->path);
}
+static gboolean client_send_changed(gpointer data)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter, array;
+
+ DBG("");
+
+ clients_notify->id = 0;
+
+ signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "TetheringClientsChanged");
+ if (!signal)
+ return FALSE;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+
+ g_hash_table_foreach(clients_table, append_client, &array);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+
+ g_hash_table_foreach(clients_notify->remove, append_client, &array);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ dbus_connection_send(connection, signal, NULL);
+ dbus_message_unref(signal);
+
+ g_hash_table_remove_all(clients_notify->remove);
+
+ return FALSE;
+}
+
+static void client_schedule_changed(void)
+{
+ if (clients_notify->id != 0)
+ return;
+
+ clients_notify->id = g_timeout_add(100, client_send_changed, NULL);
+}
+
+static void client_added(const char *addr)
+{
+ DBG("client %s", addr);
+
+ g_hash_table_remove(clients_notify->remove, addr);
+
+ client_schedule_changed();
+}
+
+static void client_removed(const char *addr)
+{
+ DBG("client %s", addr);
+
+ g_hash_table_replace(clients_notify->remove, g_strdup(addr), NULL);
+
+ client_schedule_changed();
+}
+
int __connman_private_network_request(DBusMessage *msg, const char *owner)
{
struct connman_private_network *pn;
@@ -690,6 +629,18 @@ int __connman_private_network_release(const char *path)
return 0;
}
+void __connman_tethering_client_register(const char *addr)
+{
+ g_hash_table_insert(clients_table, g_strdup(addr), NULL);
+ client_added(addr);
+}
+
+void __connman_tethering_client_unregister(const char *addr)
+{
+ g_hash_table_remove(clients_table, addr);
+ client_removed(addr);
+}
+
int __connman_tethering_init(void)
{
DBG("");
@@ -703,9 +654,12 @@ int __connman_tethering_init(void)
pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_private_network);
- sta_hash = g_hash_table_new_full(g_str_hash,
- g_str_equal, NULL, NULL);
+ clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+ clients_notify = g_new0(struct _clients_notify, 1);
+ clients_notify->remove = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
return 0;
}
@@ -726,7 +680,13 @@ void __connman_tethering_cleanup(void)
return;
g_hash_table_destroy(pn_hash);
- g_hash_table_foreach(sta_hash, destroy_station, NULL);
- g_hash_table_destroy(sta_hash);
+
+ g_hash_table_destroy(clients_notify->remove);
+ g_free(clients_notify);
+ clients_notify = NULL;
+
+ g_hash_table_destroy(clients_table);
+ clients_table = NULL;
+
dbus_connection_unref(connection);
}
diff --git a/src/timeserver.c b/src/timeserver.c
index e4cfc062..c6103466 100755
--- a/src/timeserver.c
+++ b/src/timeserver.c
@@ -34,17 +34,31 @@
#define TS_RECHECK_INTERVAL 7200
+static struct connman_service *ts_service;
+static GSList *timeservers_list = NULL;
static GSList *ts_list = NULL;
static char *ts_current = NULL;
static int ts_recheck_id = 0;
+static int ts_backoff_id = 0;
static GResolv *resolv = NULL;
static int resolv_id = 0;
+static void sync_next(void);
+
static void resolv_debug(const char *str, void *data)
{
connman_info("%s: %s\n", (const char *) data, str);
}
+
+static void ntp_callback(bool success, void *user_data)
+{
+ DBG("success %d", success);
+
+ if (!success)
+ sync_next();
+}
+
static void save_timeservers(char **servers)
{
GKeyFile *keyfile;
@@ -62,8 +76,6 @@ static void save_timeservers(char **servers)
__connman_storage_save_global(keyfile);
g_key_file_free(keyfile);
-
- return;
}
static char **load_timeservers(void)
@@ -101,35 +113,60 @@ static void resolv_result(GResolvResultStatus status, char **results,
if (status == G_RESOLV_RESULT_STATUS_SUCCESS) {
if (results) {
- for (i = 0; results[i]; i++) {
+ /* prepend the results in reverse order */
+
+ for (i = 0; results[i]; i++)
+ /* count */;
+ i--;
+
+ for (; i >= 0; i--) {
DBG("result[%d]: %s", i, results[i]);
- if (i == 0)
- continue;
ts_list = __connman_timeserver_add_list(
- ts_list, results[i]);
+ ts_list, results[i]);
}
+ }
+ }
- DBG("Using timeserver %s", results[0]);
+ sync_next();
+}
- __connman_ntp_start(results[0]);
+/*
+ * Once the timeserver list (timeserver_list) is created, we start
+ * querying the servers one by one. If resolving fails on one of them,
+ * we move to the next one. The user can enter either an IP address or
+ * a URL for the timeserver. We only resolve the URLs. Once we have an
+ * IP for the NTP server, we start querying it for time corrections.
+ */
+static void timeserver_sync_start(void)
+{
+ GSList *list;
- return;
- }
+ for (list = timeservers_list; list; list = list->next) {
+ char *timeserver = list->data;
+
+ ts_list = g_slist_prepend(ts_list, g_strdup(timeserver));
}
+ ts_list = g_slist_reverse(ts_list);
+
+ sync_next();
+}
+
+static gboolean timeserver_sync_restart(gpointer user_data)
+{
+ timeserver_sync_start();
+ ts_backoff_id = 0;
- /* If resolving fails, move to the next server */
- __connman_timeserver_sync_next();
+ return FALSE;
}
/*
- * Once the timeserver list (ts_list) is created, we start querying the
- * servers one by one. If resolving fails on one of them, we move to the
- * next one. The user can enter either an IP address or a URL for the
- * timeserver. We only resolve the URLs. Once we have an IP for the NTP
- * server, we start querying it for time corrections.
+ * Select the next time server from the working list (ts_list) because
+ * for some reason the first time server in the list didn't work. If
+ * none of the server did work we start over with the first server
+ * with a backoff.
*/
-void __connman_timeserver_sync_next()
+static void sync_next(void)
{
if (ts_current) {
g_free(ts_current);
@@ -138,34 +175,30 @@ void __connman_timeserver_sync_next()
__connman_ntp_stop();
- /* Get the 1st server in the list */
- if (!ts_list)
- return;
-
- ts_current = ts_list->data;
-
- ts_list = g_slist_delete_link(ts_list, ts_list);
-
- /* if it's an IP, directly query it. */
- if (connman_inet_check_ipaddress(ts_current) > 0) {
- DBG("Using timeserver %s", ts_current);
+ while (ts_list) {
+ ts_current = ts_list->data;
+ ts_list = g_slist_delete_link(ts_list, ts_list);
- __connman_ntp_start(ts_current);
-
- return;
- }
-
- DBG("Resolving timeserver %s", ts_current);
+ /* if it's an IP, directly query it. */
+ if (connman_inet_check_ipaddress(ts_current) > 0) {
+ DBG("Using timeserver %s", ts_current);
+ __connman_ntp_start(ts_current, ntp_callback, NULL);
+ return;
+ }
+ DBG("Resolving timeserver %s", ts_current);
#if defined TIZEN_EXT
- resolv_id = g_resolv_lookup_hostname(resolv, ts_current,
+ resolv_id = g_resolv_lookup_hostname(resolv, ts_current,
resolv_result, ts_current);
#else
- resolv_id = g_resolv_lookup_hostname(resolv, ts_current,
+ resolv_id = g_resolv_lookup_hostname(resolv, ts_current,
resolv_result, NULL);
#endif
+ return;
+ }
- return;
+ DBG("No timeserver could be used, restart probing in 5 seconds");
+ ts_backoff_id = g_timeout_add_seconds(5, timeserver_sync_restart, NULL);
}
GSList *__connman_timeserver_add_list(GSList *server_list,
@@ -218,22 +251,22 @@ GSList *__connman_timeserver_get_all(struct connman_service *service)
for (i = 0; service_ts && service_ts[i]; i++)
list = __connman_timeserver_add_list(list, service_ts[i]);
-#if defined TIZEN_EXT
- if (connman_setting_get_bool("UseGatewayTimeserver")) {
-#endif
- network = __connman_service_get_network(service);
- if (network) {
- index = connman_network_get_index(network);
- service_gw = __connman_ipconfig_get_gateway_from_index(index,
- CONNMAN_IPCONFIG_TYPE_ALL);
-
- /* Then add Service Gateway to the list */
- if (service_gw)
- list = __connman_timeserver_add_list(list, service_gw);
- }
-#if defined TIZEN_EXT
+ /*
+ * Then add Service Gateway to the list, if UseGatewaysAsTimeservers
+ * configuration option is set to true.
+ */
+ if (connman_setting_get_bool("UseGatewaysAsTimeservers")) {
+ network = __connman_service_get_network(service);
+ if (network) {
+ index = connman_network_get_index(network);
+ service_gw = __connman_ipconfig_get_gateway_from_index(index,
+ CONNMAN_IPCONFIG_TYPE_ALL);
+
+ if (service_gw)
+ list = __connman_timeserver_add_list(list, service_gw);
+ }
}
-#endif
+
/* Then add Global Timeservers to the list */
timeservers = load_timeservers();
@@ -255,7 +288,7 @@ static gboolean ts_recheck(gpointer user_data)
{
GSList *ts;
- ts = __connman_timeserver_get_all(__connman_service_get_default());
+ ts = __connman_timeserver_get_all(connman_service_get_default());
if (!ts) {
DBG("timeservers disabled");
@@ -288,6 +321,11 @@ static void ts_recheck_disable(void)
g_source_remove(ts_recheck_id);
ts_recheck_id = 0;
+ if (ts_backoff_id) {
+ g_source_remove(ts_backoff_id);
+ ts_backoff_id = 0;
+ }
+
if (ts_current) {
g_free(ts_current);
ts_current = NULL;
@@ -316,11 +354,14 @@ int __connman_timeserver_sync(struct connman_service *default_service)
if (default_service)
service = default_service;
else
- service = __connman_service_get_default();
+ service = connman_service_get_default();
if (!service)
return -EINVAL;
+ if (service == ts_service)
+ return -EALREADY;
+
if (!resolv)
return 0;
/*
@@ -346,20 +387,21 @@ int __connman_timeserver_sync(struct connman_service *default_service)
g_strfreev(nameservers);
- g_slist_free_full(ts_list, g_free);
+ g_slist_free_full(timeservers_list, g_free);
- ts_list = __connman_timeserver_get_all(service);
+ timeservers_list = __connman_timeserver_get_all(service);
- __connman_service_timeserver_changed(service, ts_list);
+ __connman_service_timeserver_changed(service, timeservers_list);
- if (!ts_list) {
+ if (!timeservers_list) {
DBG("No timeservers set.");
return 0;
}
ts_recheck_enable();
- __connman_timeserver_sync_next();
+ ts_service = service;
+ timeserver_sync_start();
return 0;
}
@@ -376,8 +418,6 @@ static int timeserver_start(struct connman_service *service)
return -EINVAL;
nameservers = connman_service_get_nameservers(service);
- if (!nameservers)
- return -EINVAL;
/* Stop an already ongoing resolution, if there is one */
if (resolv && resolv_id > 0)
@@ -398,10 +438,12 @@ static int timeserver_start(struct connman_service *service)
if (getenv("CONNMAN_RESOLV_DEBUG"))
g_resolv_set_debug(resolv, resolv_debug, "RESOLV");
- for (i = 0; nameservers[i]; i++)
- g_resolv_add_nameserver(resolv, nameservers[i], 53, 0);
+ if (nameservers) {
+ for (i = 0; nameservers[i]; i++)
+ g_resolv_add_nameserver(resolv, nameservers[i], 53, 0);
- g_strfreev(nameservers);
+ g_strfreev(nameservers);
+ }
return __connman_timeserver_sync(service);
}
@@ -410,13 +452,17 @@ static void timeserver_stop(void)
{
DBG(" ");
+ ts_service = NULL;
+
if (resolv) {
g_resolv_unref(resolv);
resolv = NULL;
}
- g_slist_free_full(ts_list, g_free);
+ g_slist_free_full(timeservers_list, g_free);
+ timeservers_list = NULL;
+ g_slist_free_full(ts_list, g_free);
ts_list = NULL;
__connman_ntp_stop();
@@ -449,7 +495,7 @@ static void default_changed(struct connman_service *default_service)
timeserver_stop();
}
-static struct connman_notifier timeserver_notifier = {
+static const struct connman_notifier timeserver_notifier = {
.name = "timeserver",
.default_changed = default_changed,
};
diff --git a/src/timezone.c b/src/timezone.c
index e346b11a..8e912670 100755
--- a/src/timezone.c
+++ b/src/timezone.c
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
diff --git a/src/util.c b/src/util.c
index 732d4512..03b14cdc 100755
--- a/src/util.c
+++ b/src/util.c
@@ -91,3 +91,14 @@ void __connman_util_cleanup(void)
f = -1;
}
+
+/**
+ * Return a random delay in range of zero to secs*1000 milli seconds.
+ */
+unsigned int __connman_util_random_delay_ms(unsigned int secs)
+{
+ uint64_t rand;
+
+ __connman_util_get_random(&rand);
+ return rand % (secs * 1000);
+}
diff --git a/src/wispr.c b/src/wispr.c
index f5fe36b4..57abdf1e 100644
--- a/src/wispr.c
+++ b/src/wispr.c
@@ -568,7 +568,7 @@ static void wispr_portal_browser_reply_cb(struct connman_service *service,
}
/* Restarting the test */
- __connman_wispr_start(service, wp_context->type);
+ __connman_service_wispr_start(service, wp_context->type);
}
static void wispr_portal_request_wispr_login(struct connman_service *service,
diff --git a/src/wpad.c b/src/wpad.c
index b7f1f1e5..f50e4dd0 100755
--- a/src/wpad.c
+++ b/src/wpad.c
@@ -87,7 +87,7 @@ static void wpad_result(GResolvResultStatus status,
g_free(url);
- __connman_wispr_start(wpad->service,
+ __connman_service_wispr_start(wpad->service,
CONNMAN_IPCONFIG_TYPE_IPV4);
return;
@@ -119,7 +119,7 @@ failed:
connman_service_set_proxy_method(wpad->service,
CONNMAN_SERVICE_PROXY_METHOD_DIRECT);
- __connman_wispr_start(wpad->service,
+ __connman_service_wispr_start(wpad->service,
CONNMAN_IPCONFIG_TYPE_IPV4);
}