[PATCH] Force BSS expiration
by Yasser
We were having a problem with our wifi scanning, where the list of
wifi available would become empty and would not be repopulated until
after a long delay. Researching the problem it seemed that it was
related to BSS expiration age. There were already some people who had
faced the same issue, so inspired by this we developed the following
patch which allows us to set the BSS expiration age to match ConnMan
long scanning interval to avoid the loss of networks during a long
interval between two scans.
diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index bfb52db..08d6b9e 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -267,7 +267,8 @@ int
g_supplicant_interface_connect(GSupplicantInterface *interface,
int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
GSupplicantInterfaceCallback callback,
void *user_data);
-
+int g_supplicant_interface_set_bss_expiration_age(GSupplicantInterface
*interface,
+ unsigned int
bss_expiration_age);
int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
unsigned int ap_scan);
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index 6052f7b..fe6ad48 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -981,6 +981,46 @@ static void interface_capability(const char *key,
DBusMessageIter *iter,
key, dbus_message_iter_get_arg_type(iter));
}
+struct g_supplicant_bss_expiration_age
+{
+ GSupplicantInterface *interface;
+ unsigned int bss_expiration_age;
+};
+
+static void set_bss_expiration_age(DBusMessageIter *iter, void *user_data)
+{
+ struct g_supplicant_bss_expiration_age *data = user_data;
+ unsigned int bss_expiration_age = data->bss_expiration_age;
+
+ dbus_free(data);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32,
&bss_expiration_age);
+}
+
+int g_supplicant_interface_set_bss_expiration_age(GSupplicantInterface
*interface,
+ unsigned int
bss_expiration_age)
+{
+ struct g_supplicant_bss_expiration_age *data;
+ int ret;
+
+ data = dbus_malloc0(sizeof(*data));
+
+ if (!data)
+ return -ENOMEM;
+
+ data->bss_expiration_age = bss_expiration_age;
+ data->interface = interface;
+
+ ret = supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface",
+ "BSSExpireAge", DBUS_TYPE_UINT32_AS_STRING,
+ set_bss_expiration_age, NULL, data, NULL);
+ if (ret < 0)
+ dbus_free(data);
+
+ return ret;
+}
+
+
struct set_apscan_data
{
unsigned int ap_scan;
diff --git a/plugins/wifi.c b/plugins/wifi.c
index 910b739..57b63e2 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -1522,6 +1522,7 @@ static void interface_create_callback(int result,
void *user_data)
{
struct wifi_data *wifi = user_data;
+ char * bgscan_range_max;
DBG("result %d ifname %s, wifi %p", result,
g_supplicant_interface_get_ifname(interface),
@@ -1537,6 +1538,13 @@ static void interface_create_callback(int result,
wifi->interface_ready = true;
finalize_interface_creation(wifi);
}
+ /* Force the BSS expiration age to match ConnMan long scanning
interval to avoid the loss of networks during a long interval between
two scannings. */
+ if ((bgscan_range_max = strrchr(BGSCAN_DEFAULT,':')) != NULL &&
+
g_supplicant_interface_set_bss_expiration_age(interface,
strtol(bgscan_range_max + 1, (char**)NULL, 10) + 10) >= 0) {
+ DBG("bss expiration age successfully updated");
+ } else {
+ DBG("bss expiration age update has failed");
+ }
}
static int wifi_enable(struct connman_device *device)
1 year, 6 months
ipv6 test web page down
by KeithG
DOn't know if this is the right place or not, but since moving to connman,
I have noticed that the ipv6 test page is down. the ipv4 one works fine,
but I get a mention in the log:
"connmand[254]: Failed to find URL:
http://ipv6.connman.net/online/status.html"
If I try to get to it from a browser, I get a '502 bad gateway error'
If I use curl on the cli, I get this:
# curl ipv4.connman.net/online/status.html
<html>
<head>
</head>
<body>
</body>
</html>
# curl ipv6.connman.net/online/status.html
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx</center>
</body>
</html>
I think something is not set right on the server...
Keith
1 year, 8 months
[PATCH] IP Accounting for WiFi Clients
by Aravind Gunasekaran
diff --git a/Makefile.am b/Makefile.am
old mode 100644
new mode 100755
index 5971ca9..44148df
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ include_HEADERS = include/log.h include/plugin.h \
include/storage.h include/provision.h \
include/session.h include/ipaddress.h include/agent.h \
include/inotify.h include/peer.h include/machine.h \
- include/acd.h include/tethering.h
+ include/acd.h include/tethering.h include/accounting-iptables.h
nodist_include_HEADERS = include/version.h
@@ -152,7 +152,7 @@ src_connmand_wait_online_LDADD = gdbus/
libgdbus-internal.la \
@GLIB_LIBS@ @DBUS_LIBS@
if XTABLES
-src_connmand_SOURCES += src/iptables.c src/firewall-iptables.c
+src_connmand_SOURCES += src/iptables.c src/firewall-iptables.c
src/accounting-iptables.c
src_connmand_LDADD += @XTABLES_LIBS@
endif
diff --git a/include/accounting-iptables.h b/include/accounting-iptables.h
new file mode 100755
index 0000000..3a9cc30
--- /dev/null
+++ b/include/accounting-iptables.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2013 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
+ *
+ */
+
+#ifndef __CONNMAN_ACCOUNTING_IPTABLES_H
+#define __CONNMAN_ACCOUNTING_IPTABLES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct counters {
+ __u64 pcnt, bcnt; /* Packet and byte counters */
+};
+
+struct ip_accounting_info {
+ char *ipv4_address; /* IP address of the client */
+ struct counters egress; /* Transmitted bytes information of the client */
+ struct counters ingress; /* Received bytes information of the client */
+};
+
+int __connman_get_ip_acc_info(struct ip_accounting_info *ip_acc);
+int __connman_add_ip_acc_rules(char *ip_addrs);
+int __connman_delete_ip_acc_rules(char *ip_addrs);
+int __connman_create_ip_acc_chain(char *ifname);
+int __connman_destroy_ip_acc_chain(char *ifname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_ACCOUNTING_IPTABLES_H */
diff --git a/src/accounting-iptables.c b/src/accounting-iptables.c
new file mode 100755
index 0000000..e5b45d9
--- /dev/null
+++ b/src/accounting-iptables.c
@@ -0,0 +1,367 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2013 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
+ *
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.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"
+
+#define CHAIN_PREFIX "connman-"
+#define INGRESS_IP_ACC (CHAIN_PREFIX"INGRESS_IP_ACC")
+#define EGRESS_IP_ACC (CHAIN_PREFIX"EGRESS_IP_ACC")
+
+struct iptables_entry {
+ int type;
+ unsigned int offset;
+ int builtin;
+ int counter_idx;
+ struct ipt_entry *entry;
+ struct ip6t_entry *entry6;
+};
+
+static int get_ingress_ip_acc_info(int type, const char *table_name, const
char *chain, struct ip_accounting_info *ip_acc)
+{
+ GList *chain_head, *chain_tail, *list, *next;
+ char src_ip_addrs[INET_ADDRSTRLEN], dst_ip_addrs[INET_ADDRSTRLEN];
+ struct iptables_entry *entry;
+ int err = 0;
+
+ DBG("%d -t %s -L %s", type, table_name, chain);
+
+ err = __connman_iptables_get_chain(type, table_name, chain, &chain_head,
&chain_tail);
+
+ if (err < 0) {
+ return err;
+ }
+
+ list = chain_head;
+
+ // if no entry
+ if (list == chain_tail->prev) {
+ DBG("No entries found for this %s chain", chain);
+ return 0;
+ }
+
+ // traversing through the entries
+ while (list != chain_tail->prev) {
+ entry = list->data;
+ next = g_list_next(list);
+ // check for IPv4 Entries
+ if (entry->type == AF_INET) {
+ if (inet_ntop(entry->type, &entry->entry->ip.src, &src_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 source address");
+ return -EINVAL;
+ }
+ if (inet_ntop(entry->type, &entry->entry->ip.dst, &dst_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 destination address");
+ return -EINVAL;
+ }
+ DBG("src %s dst %s packets %"PRIu64" ""bytes %"PRIu64, src_ip_addrs,
dst_ip_addrs
+ , (uint64_t)entry->entry->counters.pcnt,
(uint64_t)entry->entry->counters.bcnt);
+
+ if (!strcmp(src_ip_addrs, ip_acc->ipv4_address)) {
+ ip_acc->ingress.pcnt = entry->entry->counters.pcnt;
+ ip_acc->ingress.bcnt = entry->entry->counters.bcnt;
+ break;
+ }
+
+ }
+ list = next;
+ }
+ return 0;
+}
+
+static int get_egress_ip_acc_info(int type, const char *table_name, const
char *chain, struct ip_accounting_info *ip_acc)
+{
+ GList *chain_head, *chain_tail, *list, *next;
+ char src_ip_addrs[INET_ADDRSTRLEN], dst_ip_addrs[INET_ADDRSTRLEN];
+ struct iptables_entry *entry;
+ int err = 0;
+
+ DBG("%d -t %s -L %s", type, table_name, chain);
+
+ err = __connman_iptables_get_chain(type, table_name, chain, &chain_head,
&chain_tail);
+
+ if (err < 0) {
+ return err;
+ }
+
+ list = chain_head;
+
+ // if no entry
+ if (list == chain_tail->prev) {
+ DBG("No entries found for this %s chain", chain);
+ return 0;
+ }
+
+ // traversing through the entries
+ while (list != chain_tail->prev) {
+ entry = list->data;
+ next = g_list_next(list);
+ // check for IPv4 Entries
+ if (entry->type == AF_INET) {
+ if (inet_ntop(entry->type, &entry->entry->ip.src, &src_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 source address");
+ return -EINVAL;
+ }
+ if (inet_ntop(entry->type, &entry->entry->ip.dst, &dst_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 destination address");
+ return -EINVAL;
+ }
+ DBG("src %s dst %s packets %"PRIu64" ""bytes %"PRIu64, src_ip_addrs,
dst_ip_addrs
+ , (uint64_t)entry->entry->counters.pcnt,
(uint64_t)entry->entry->counters.bcnt);
+
+ if (!strcmp(dst_ip_addrs, ip_acc->ipv4_address)) {
+ ip_acc->egress.pcnt = entry->entry->counters.pcnt;
+ ip_acc->egress.bcnt = entry->entry->counters.bcnt;
+ break;
+ }
+
+ }
+ list = next;
+ }
+
+ return 0;
+}
+
+int __connman_get_ip_acc_info(struct ip_accounting_info *ip_acc)
+{
+ char *user_defined_chain;
+ int err = 0;
+
+ // get ip accounting for ingress packets
+ DBG("get ip accounting ingress info for ipv4 address (%s)",
ip_acc->ipv4_address);
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ err = get_ingress_ip_acc_info(2, "filter", user_defined_chain, ip_acc);
+ if (err < 0) {
+ DBG("failed to get ip accounting from ingress chain %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+
+ // get ip accounting for egress packets
+ DBG("get ip accounting egress info for ipv4 address (%s)",
ip_acc->ipv4_address);
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ err = get_egress_ip_acc_info(2, "filter", user_defined_chain, ip_acc);
+ if (err < 0) {
+ DBG("failed to get ip accounting from egress chain %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+
+ return err;
+}
+
+int __connman_add_ip_acc_rules(char *ip_addrs)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_rule = NULL;
+ int err = 0;
+
+ // Adding the ingress ip accounting rules
+ DBG("adding ip accounting ingress rules for ipv4 address (%s)", ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-s %s", ip_addrs);
+ err = __connman_iptables_append(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to add %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ // Adding the egress ip accounting rules
+ DBG("adding ip accounting egress rules for ipv4 address (%s)", ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-d %s", ip_addrs);
+ err = __connman_iptables_append(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to add %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ //committing the rules to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+
+ return err;
+}
+
+int __connman_delete_ip_acc_rules(char *ip_addrs)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_rule = NULL;
+ int err = 0;
+
+ // Deleting the ingress ip accounting rules
+ DBG("deleting ip accounting ingress rules for ipv4 address (%s)",
ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-s %s/32 -j ACCEPT", ip_addrs);
+ err = __connman_iptables_delete(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to delete %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ //Deleting the egress ip accounting rules
+ DBG("deleting ip accounting egress rules for ipv4 address (%s)",
ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-d %s/32 -j ACCEPT", ip_addrs);
+ err = __connman_iptables_delete(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to delete %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ //committing the rules to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+
+ return err;
+}
+
+int __connman_create_ip_acc_chain(char *ifname)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_entry = NULL;
+ int err = 0;
+
+ // creating user defined chain for ingress ip accounting
+ DBG("creating ip accounting chain for ingress");
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ err = __connman_iptables_new_chain(AF_INET, "filter", user_defined_chain);
+ if (err < 0) {
+ DBG("failed to create new chain -t filter %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ user_defined_entry = g_strdup_printf("-i %s -j %s", ifname,
user_defined_chain);
+ err = __connman_iptables_insert(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to insert entry -t filter %s, error:(%d/%s)",
user_defined_entry, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ // creating user defined chain for egress ip accounting
+ DBG("creating ip accounting chain for egress");
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ err = __connman_iptables_new_chain(AF_INET, "filter", user_defined_chain);
+ if (err < 0) {
+ DBG("failed to create new chain -t filter %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ user_defined_entry = g_strdup_printf("-o %s -j %s", ifname,
user_defined_chain);
+ err = __connman_iptables_insert(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to insert entry -t filter %s, error:(%d/%s)",
user_defined_entry, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ //committing the ip accounting chain to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+ return err;
+}
+
+int __connman_destroy_ip_acc_chain(char *ifname)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_entry = NULL;
+ int err = 0;
+
+ // Deleting user defined chain for ingress ip accounting
+ DBG("deleting ip accounting rules for ingress");
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ user_defined_entry = g_strdup_printf("-i %s -j %s", ifname,
user_defined_chain);
+ // Delete rule, if any
+ err = __connman_iptables_delete(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to delete -D FORWARD %s, error:(%d/%s)", user_defined_entry,
-err, strerror(-err));
+ }
+ // Flush rules, if any
+ DBG("flush ip accounting chain for ingress");
+ err = __connman_iptables_flush_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("failed to flush chain -F %s, error:(%d/%s)", user_defined_chain,
-err, strerror(-err));
+ }
+ // Delete the chain
+ DBG("deleting ip accounting chain for ingress");
+ err = __connman_iptables_delete_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("failed to delete chain -X %s, error:(%d/%s)", user_defined_chain,
-err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ // Deleting user defined chain for egress ip accounting
+ DBG("deleting ip accounting rules for egress");
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ user_defined_entry = g_strdup_printf("-o %s -j %s", ifname,
user_defined_chain);
+ // Delete rule, if any
+ err = __connman_iptables_delete(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to delete -D FORWARD %s, error:(%d/%s)", user_defined_entry,
-err, strerror(-err));
+ }
+ // Flush rules, if any
+ DBG("flush ip accounting chain for egress");
+ err = __connman_iptables_flush_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("failed to flush chain -F %s, error:(%d/%s)", user_defined_chain,
-err, strerror(-err));
+ }
+ // Delete the chain
+ DBG("deleting ip accounting chain for egress");
+ err = __connman_iptables_delete_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("Failed to delete chain -X %s: %s", user_defined_chain,
strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ //committing the rules to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+
+ return err;
+}
diff --git a/src/connman.h b/src/connman.h
old mode 100644
new mode 100755
index 3bdc0dc..3530937
--- a/src/connman.h
+++ b/src/connman.h
@@ -951,6 +951,11 @@ int __connman_iptables_delete(int type,
const char *table_name,
const char *chain,
const char *rule_spec);
+int __connman_iptables_get_chain(int type,
+ const char *table_name,
+ const char *chain,
+ GList **chain_head,
+ GList **chain_tail);
typedef void (*connman_iptables_iterate_chains_cb_t) (const char
*chain_name,
void *user_data);
@@ -1015,6 +1020,8 @@ int __connman_nat_enable(const char *name, const char
*address,
unsigned char prefixlen);
void __connman_nat_disable(const char *name);
+#include <connman/accounting-iptables.h>
+
struct firewall_context;
struct firewall_context *__connman_firewall_create(void);
diff --git a/src/iptables.c b/src/iptables.c
old mode 100644
new mode 100755
index 47ea1c2..f4e0e74
--- a/src/iptables.c
+++ b/src/iptables.c
@@ -3646,6 +3646,48 @@ int __connman_iptables_dump(int type, const char
*table_name)
return 0;
}
+int __connman_iptables_get_chain(int type,
+ const char *table_name,
+ const char *chain,
+ GList **chain_head,
+ GList **chain_tail)
+{
+ GList *list, *next;
+ struct connman_iptables_entry *entry;
+ struct connman_iptables *table = NULL;
+ int builtin;
+
+ table = iptables_init(type, table_name);
+
+ if (!table)
+ return -EINVAL;
+
+ DBG("table %s chain %s", table->name, chain);
+
+ // finding the chain head
+ *chain_head = find_chain_head(table, chain);
+ if (!*chain_head)
+ return -EINVAL;
+
+ // finding the chain tail
+ *chain_tail = find_chain_tail(table, chain);
+ if (!*chain_tail)
+ return -EINVAL;
+
+ entry = (*chain_head)->data;
+ builtin = entry->builtin;
+
+ //if it builtin chain then interate starts from head
+ if (builtin >= 0)
+ list = *chain_head;
+ else
+ list = (*chain_head)->next;
+
+ *chain_head = list;
+
+ return 0;
+}
+
int __connman_iptables_new_chain(int type,
const char *table_name,
const char *chain)
diff --git a/src/manager.c b/src/manager.c
old mode 100644
new mode 100755
index 3bf8f4e..0e1bc7e
--- a/src/manager.c
+++ b/src/manager.c
@@ -227,8 +227,13 @@ static DBusMessage
*get_tethering_clients(DBusConnection *conn,
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &array);
-
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING, &array);
__connman_tethering_list_clients(&array);
dbus_message_iter_close_container(&iter, &array);
diff --git a/src/tethering.c b/src/tethering.c
old mode 100644
new mode 100755
index e2687b6..e80d4c3
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -50,6 +50,8 @@
#define BRIDGE_NAME "tether"
+#define IP_NOT_OFFERED ("not offered")
+
#define DEFAULT_MTU 1500
static char *private_network_primary_dns = NULL;
@@ -61,7 +63,7 @@ static struct connman_ippool *dhcp_ippool = NULL;
static DBusConnection *connection;
static GHashTable *pn_hash;
-static GHashTable *clients_table;
+static GHashTable *added_clients_table, *removed_clients_table;
struct _clients_notify {
int id;
@@ -139,6 +141,64 @@ static void dhcp_server_error(GDHCPServerError error)
}
}
+struct ip_accounting_info *tether_client_create(void)
+{
+ struct ip_accounting_info *tether_client;
+
+ tether_client = g_try_new0(struct ip_accounting_info, 1);
+ if (!tether_client)
+ return NULL;
+
+ tether_client->ipv4_address = g_strdup(IP_NOT_OFFERED);
+ tether_client->ingress.bcnt = 0;
+ tether_client->ingress.bcnt = 0;
+ tether_client->egress.bcnt = 0;
+ tether_client->egress.bcnt = 0;
+ return tether_client;
+}
+
+static void lease_added(unsigned char *mac, uint32_t ipv4)
+{
+ char mac_addr[18];
+ struct in_addr addr;
+ struct ip_accounting_info *teth_cli = NULL;
+
+ snprintf(mac_addr, 18,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+
+ addr.s_addr = ipv4;
+ char *ip_addr = inet_ntoa(addr);
+
+ DBG("ipv4 address(%s) leased for client mac(%s)", ip_addr, mac_addr);
+
+ if (true == g_hash_table_lookup_extended(added_clients_table,
+ mac_addr,
+ NULL, &teth_cli)) {
+ if (!strcmp(teth_cli->ipv4_address, g_strdup(IP_NOT_OFFERED))) {
+ // ipv4 address is not offered, it new client
+ DBG("new ip address is offered to new client");
+ g_free(teth_cli->ipv4_address);
+ teth_cli->ipv4_address = g_strdup(ip_addr);
+ __connman_add_ip_acc_rules(teth_cli->ipv4_address);
+ } else if (strcmp(teth_cli->ipv4_address, ip_addr)) {
+ // new ipv4 address is assigned, may be lease expired
+ DBG("new ip address is offered to existing client, may be lease expired");
+ __connman_delete_ip_acc_rules(teth_cli->ipv4_address);
+ g_free(teth_cli->ipv4_address);
+ teth_cli->ipv4_address = g_strdup(ip_addr);
+ __connman_add_ip_acc_rules(teth_cli->ipv4_address);
+ } else {
+ // sometime lease_added is called multiple time and ipv4 address is same
+ DBG("already ip address is offered to this client");
+ }
+ } else {
+ // possibly this situation will not happen
+ DBG("client is not authorised/registered, fatal error!");
+ }
+}
+
static GDHCPServer *dhcp_server_start(const char *bridge,
const char *router, const char *subnet,
const char *start_ip, const char *end_ip,
@@ -167,6 +227,7 @@ static GDHCPServer *dhcp_server_start(const char
*bridge,
g_dhcp_server_set_option(dhcp_server, G_DHCP_ROUTER, router);
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_lease_added_cb(dhcp_server, lease_added);
g_dhcp_server_start(dhcp_server);
@@ -195,9 +256,42 @@ static void unregister_client(gpointer key,
__connman_tethering_client_unregister(addr);
}
+static void tether_client_copy(gpointer key,
+ gpointer value, gpointer user_data)
+{
+ GHashTable *tether_client_table = user_data;
+ struct ip_accounting_info *copy_teth_client;
+ struct ip_accounting_info *tether_client = value;
+
+ copy_teth_client = tether_client_create();
+ if (tether_client) {
+ copy_teth_client->ipv4_address = g_strdup(tether_client->ipv4_address);
+ g_hash_table_insert(tether_client_table, g_strdup(key), copy_teth_client);
+ } else {
+ DBG("could not create tether client entry");
+ }
+}
+
+static void tether_client_destroy(gpointer data)
+{
+ struct ip_accounting_info *tether_client = data;
+
+ g_free(tether_client->ipv4_address);
+ g_free(tether_client);
+}
+
static void unregister_all_clients(void)
{
- g_hash_table_foreach(clients_table, unregister_client, NULL);
+ GHashTable *tether_client_table;
+
+ tether_client_table = g_hash_table_new_full(g_str_hash,
+ g_str_equal,
+ g_free,
+ tether_client_destroy);
+ g_hash_table_foreach(added_clients_table, tether_client_copy,
+ tether_client_table);
+ g_hash_table_foreach(tether_client_table, unregister_client, NULL);
+ g_hash_table_destroy(tether_client_table);
}
int __connman_tethering_set_enabled(void)
@@ -306,6 +400,8 @@ int __connman_tethering_set_enabled(void)
DBG("Cannot setup IPv6 prefix delegation %d/%s", err,
strerror(-err));
+ __connman_create_ip_acc_chain(BRIDGE_NAME);
+
DBG("tethering started");
return 0;
@@ -345,9 +441,60 @@ void __connman_tethering_set_disabled(void)
g_free(private_network_secondary_dns);
private_network_secondary_dns = NULL;
+ __connman_destroy_ip_acc_chain(BRIDGE_NAME);
+
DBG("tethering stopped");
}
+static void append_dict_properties(DBusMessageIter *dict,
+ struct ip_accounting_info *tether_client,
+ char *addr)
+{
+ struct ip_accounting_info *removed_tether_client = NULL;
+
+ connman_dbus_dict_append_basic(dict, "mac", DBUS_TYPE_STRING, &addr);
+
+ connman_dbus_dict_append_basic(dict, "ipv4", DBUS_TYPE_STRING,
+ &tether_client->ipv4_address);
+
+ __connman_get_ip_acc_info(tether_client);
+
+ connman_dbus_dict_append_basic(dict, "tx-bytes", DBUS_TYPE_UINT64,
+ &tether_client->ingress.bcnt);
+
+ connman_dbus_dict_append_basic(dict, "rx-bytes", DBUS_TYPE_UINT64,
+ &tether_client->egress.bcnt);
+
+ removed_tether_client = g_hash_table_lookup(removed_clients_table, addr);
+ if (removed_tether_client) {
+ connman_dbus_dict_append_basic(dict, "previous tx-bytes",
+ DBUS_TYPE_UINT64,
+ &removed_tether_client->ingress.bcnt);
+ connman_dbus_dict_append_basic(dict, "previous rx-bytes",
+ DBUS_TYPE_UINT64,
+ &removed_tether_client->egress.bcnt);
+ } else {
+ DBG("no history found for this client");
+ }
+}
+
+static void append_struct_ip_acc_info(char *addr,
+ struct ip_accounting_info *tether_client,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter entry, dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
+
+ connman_dbus_dict_open(&entry, &dict);
+
+ append_dict_properties(&dict, tether_client, addr);
+
+ connman_dbus_dict_close(&entry, &dict);
+
+ dbus_message_iter_close_container(iter, &entry);
+}
+
static void append_client(gpointer key, gpointer value,
gpointer user_data)
{
@@ -360,7 +507,11 @@ static void append_client(gpointer key, gpointer value,
void __connman_tethering_list_clients(DBusMessageIter *array)
{
- g_hash_table_foreach(clients_table, append_client, array);
+ DBG("found %d clients in hash table",
+ g_hash_table_size(added_clients_table));
+
+ g_hash_table_foreach(added_clients_table, append_struct_ip_acc_info,
+ array);
}
static void setup_tun_interface(unsigned int flags, unsigned change,
@@ -494,7 +645,7 @@ static gboolean client_send_changed(gpointer data)
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING, &array);
- g_hash_table_foreach(clients_table, append_client, &array);
+ g_hash_table_foreach(added_clients_table, append_client, &array);
dbus_message_iter_close_container(&iter, &array);
@@ -631,14 +782,68 @@ int __connman_private_network_release(const char
*path)
void __connman_tethering_client_register(const char *addr)
{
- g_hash_table_insert(clients_table, g_strdup(addr), NULL);
+ struct ip_accounting_info *tether_client;
+
+ DBG("adding %s mac address in hash table", addr);
+
+ tether_client = tether_client_create();
+
+ if (tether_client)
+ g_hash_table_insert(added_clients_table, g_strdup(addr), tether_client);
+ else
+ DBG("could not create tether client entry");
+
+ DBG("hash table size %d", g_hash_table_size(added_clients_table));
+
client_added(addr);
}
void __connman_tethering_client_unregister(const char *addr)
{
- client_removed(addr);
- g_hash_table_remove(clients_table, addr);
+ struct ip_accounting_info *existing_tether_client;
+ struct ip_accounting_info *old_tether_client;
+ struct ip_accounting_info *tether_client;
+
+ DBG("removing %s mac address from hash table", addr);
+
+ existing_tether_client = g_hash_table_lookup(added_clients_table, addr);
+ if (existing_tether_client) {
+ if (strcmp(existing_tether_client->ipv4_address,
+ g_strdup(IP_NOT_OFFERED))) {
+ __connman_get_ip_acc_info(existing_tether_client);
+ __connman_delete_ip_acc_rules(existing_tether_client->ipv4_address);
+ old_tether_client = g_hash_table_lookup(removed_clients_table, addr);
+ if (old_tether_client) {
+ DBG("replacing existing client in hash table");
+ tether_client = tether_client_create();
+ if (tether_client) {
+ tether_client->ingress.bcnt = old_tether_client->ingress.bcnt
+ + existing_tether_client->ingress.bcnt;
+ tether_client->egress.bcnt = old_tether_client->egress.bcnt
+ + existing_tether_client->egress.bcnt;
+ g_hash_table_replace(removed_clients_table,
+ g_strdup(addr),
+ tether_client);
+ } else
+ DBG("could not create tether client entry");
+ } else {
+ DBG("adding client in hash table");
+ tether_client = tether_client_create();
+ if (tether_client) {
+ tether_client->ingress.bcnt = existing_tether_client->ingress.bcnt;
+ tether_client->egress.bcnt = existing_tether_client->egress.bcnt;
+ g_hash_table_insert(removed_clients_table,
+ g_strdup(addr),
+ tether_client);
+ } else
+ DBG("could not create tether client entry");
+ }
+ } else
+ DBG("ip address not offered for %s ", addr);
+ g_hash_table_remove(added_clients_table, addr);
+ client_removed(addr);
+ } else
+ DBG("could not remove client from hash table");
}
int __connman_tethering_init(void)
@@ -654,8 +859,11 @@ int __connman_tethering_init(void)
pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_private_network);
- clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, NULL);
+ added_clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, tether_client_destroy);
+
+ removed_clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, tether_client_destroy);
clients_notify = g_new0(struct _clients_notify, 1);
clients_notify->remove = g_hash_table_new_full(g_str_hash, g_str_equal,
@@ -685,8 +893,11 @@ void __connman_tethering_cleanup(void)
g_free(clients_notify);
clients_notify = NULL;
- g_hash_table_destroy(clients_table);
- clients_table = NULL;
+ g_hash_table_destroy(added_clients_table);
+ added_clients_table = NULL;
+
+ g_hash_table_destroy(removed_clients_table);
+ removed_clients_table = NULL;
dbus_connection_unref(connection);
}
--
Thanks,
Aravind
2 years
Wifi AP with a captive portal
by Stavros Vagionitis
Hi all,
I have a question regarding the agent API RequestBrowser (
https://git.kernel.org/pub/scm/network/connman/connman.git/tree/doc/agent...
).
I use connman v1.37 and I am trying to connect to a wifi AP with a
captive portal, like the ones at airports or cafes. When I do the
following using connmanctl, I don't get any URL or the URL is empty.
```
connmanctl> agent on
Agent registered
connmanctl> connect wifi_304511e7f961_67756573746e6574_managed_none
connmanctl> [6667749.907750] wlansta0: authenticate with
58:0a:20:5b:ec:cf
[6667749.942790] wlansta0: send auth to 58:0a:20:5b:ec:cf (try 1/3)
[6667750.115858] wlansta0: authenticated
[6667750.130032] wlansta0: associate with 58:0a:20:5b:ec:cf (try 1/3)
[6667750.139199] wlansta0: RX AssocResp from 58:0a:20:5b:ec:cf
(capab=0x101 status=0 aid=1)
[6667750.161632] wlansta0: associated
[6667750.171616] wlcore: Association completed.
[6667750.178102] IPv6: ADDRCONF(NETDEV_CHANGE): wlansta0: link becomes
ready
Connected wifi_304511e7f961_67756573746e6574_managed_none
Agent RequestBrowser wifi_304511e7f961_67756573746e6574_managed_none
connmanctl> Connected (yes/no)? no
```
Is this a normal behavior not to get a URL? If the URL is not provided,
is there another way to get the URL and add it to the browser?
Thanks in advance,
Stavros
2 years
Re: Wifi Tethering
by Daniel Wagner
On Sat, Apr 25, 2020 at 11:20:45AM -0500, KeithG wrote:
> I looked at the IWD readme and cannot enable this on the RPi:
>
> # ip link set dev nlmon allmulticast on
> > Cannot find device "nlmon"
The RPi kernel has no support for nlmon enabled. If you want to debug this you
propably need to compile your own RPi kernel with nlmon enabled.
> I did verify a couple things. I do have iwd set explicitly when I start
> connman
> /usr/bin/connmand --wifi=iwd_agent -n --nodnsproxy
--wifi=iwd_agent is wrong. If you want iwd support you need to define this
at compile time only:
./configure --enable-iwd --disable-wifi
which adds the iwd plugin and disables the wpa_supplicant plugin. But I don't
think it matter. --iwfi-iwd_agent will be ignored and ConnMan will dynamically
discover iwd. Just make sure wpa_supplicant is not running. With the above
command line you would make sure wpa_supplicant is not accidentally used.
> When I issue the command from connman, the mode changes in iwd:
>
> > # connmanctl tether wifi on myssid password
> > Wifi SSID set
> > Wifi passphrase set
> > Enabled tethering for wifi
> > # ip addr
> > 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group
> > default qlen 1000
> > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
> > inet 127.0.0.1/8 scope host lo
> > valid_lft forever preferred_lft forever
> > inet6 ::1/128 scope host
> > valid_lft forever preferred_lft forever
> > 2: eth0: <BROADCAST,MULTICAST,DYNAMIC,UP,LOWER_UP> mtu 1500 qdisc fq_codel
> > state UP group default qlen 1000
> > link/ether a0:ce:c8:12:ed:05 brd ff:ff:ff:ff:ff:ff
> > inet 192.168.2.25/24 brd 192.168.2.255 scope global eth0
> > valid_lft forever preferred_lft forever
> > inet6 fe80::a2ce:c8ff:fe12:ed05/64 scope link
> > valid_lft forever preferred_lft forever
> > 3: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
> > fq_codel master tether state DORMANT group default qlen 1000
> > link/ether b8:27:eb:28:18:48 brd ff:ff:ff:ff:ff:ff
> > 4: tether: <NO-CARRIER,BROADCAST,MULTICAST,DYNAMIC,UP> mtu 1500 qdisc
> > noqueue state DOWN group default qlen 1000
> > link/ether 9a:69:3a:48:c1:32 brd ff:ff:ff:ff:ff:ff
> > inet 192.168.0.1/24 brd 192.168.0.255 scope global tether
> > valid_lft forever preferred_lft forever
> > inet6 fe80::d024:5eff:fe80:1a57/64 scope link
> > valid_lft forever preferred_lft forever
> > # iwctl device wlan0 show
> > Device: wlan0
> >
> > --------------------------------------------------------------------------------
> > Settable Property Value
> >
> > --------------------------------------------------------------------------------
> > Name wlan0
> > * Mode ap
> > * Powered on
> > Address b8:27:eb:28:18:48
> > Adapter phy0
> >
>
> I get these responses in the journal when I try to connect but it never
> connects:
>
> > src/netdev.c:netdev_mlme_notify() MLME notification New Station(19)
> > src/netdev.c:netdev_mlme_notify() MLME notification Del Station(20)
> > src/netdev.c:netdev_mlme_notify() MLME notification Del Station(20)
> >
Did you try to run iwd with debug enabled 'iwd -d'? Maybe there is more
info. And if there isn't any clue, the best way forward is to get
nlmon running and provide the information the iwd developers. From what I
see ConnMan is talking to iwd and setups the AP mode.
> I currently use hostapd and dnsmasq to have this headless RPi audio
> appliance work as an AP for initial setup, but want to remove hostapd and
> dnsmasq if I can get connman/iwd to do the same thing. I tried to get iwd
> to go into ap mode and connect, but cannot do it there, either. I do get
> some messages at startup of iwd. I do not think these are the problem, but
> they are missing kernel modules:
>
> No Diffie-Hellman support found, WPS will not be available
> > No asymmetric key support found.
> > TLS based WPA-Enterprise authentication methods will not function.
> > Kernel 4.20+ is required for this feature.
> > The following options are missing in the kernel:
> > CONFIG_ASYMMETRIC_KEY_TYPE
> > CONFIG_KEY_DH_OPERATIONS
> > CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE
> > CONFIG_PKCS7_MESSAGE_PARSER
> > CONFIG_X509_CERTIFICATE_PARSER
> > CONFIG_PKCS8_PRIVATE_KEY_PARSER
> > Wireless daemon version 1.6
I don't know but I would suggest to address this in the same go when you build
a new kernel with nlmon support.
Thanks,
Daniel
2 years
Manual removal of service provisioning settings
by robertweber95@gmail.com
Hi,
I have a question regarding the ability to clean up the service provisioning settings found in /var/lib/connman/*/settings. As far as I understand, these files are internal to connman and shouldn't be manipulated manually. However, I'd like to remove old service settings frequently to prevent old and unnecessary SSID/psk combinations from staying on the device for long periods of time.
I've noticed that when switching network connections, the old service settings remain in /var/lib/connman, even if I use the service Remove() DBus method. Is it possible to remove these settings files using the DBus API?
If not, is it safe for me to remove the service directories from the filesystem manually after using DBus Remove method to remove the service?
Lastly, could you tell me a bit more about the normal behavior of the provisioning settings, such as when those files are removed by connman (if at all)?
Thanks in advance for any information you can provide!
Cheers,
Rob Weber
2 years
[PATCH] Add support to get or remove known services via command /
by Daniel Wagner
From: "Ryll, Jan (BSH)" <jan.ryll(a)bshg.com>
From: "Ryll, Jan (BSH)" <jan.ryll(a)bshg.com>
---
I'v recieved this patch directly into my inbox...
client/commands.c | 56 +++++++++++++++++++++++++++++++++++
src/connman.h | 2 ++
src/manager.c | 63 ++++++++++++++++++++++++++++++++++++++++
src/service.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/manager-api.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 285 insertions(+)
diff --git a/client/commands.c b/client/commands.c
index 05b9316..594f375 100644
--- a/client/commands.c
+++ b/client/commands.c
@@ -389,6 +389,58 @@ static int cmd_services(char *args[], int num, struct connman_option *options)
object_properties, path, NULL, NULL);
}
+static int cmd_known_services(char *args[], int num, struct connman_option *options)
+{
+ if (num > 1)
+ return -E2BIG;
+
+ return __connmanctl_dbus_method_call(connection,
+ CONNMAN_SERVICE, CONNMAN_PATH,
+ "net.connman.Manager",
+ "GetKnownServices",
+ services_list, NULL, NULL, NULL);
+}
+
+
+static int remove_known_service_return(DBusMessageIter *iter, const char *error,
+ void *user_data)
+{
+ char *path = user_data;
+
+ if (!error) {
+ char *str = strrchr(path, '/');
+ str++;
+ fprintf(stdout, "Removed %s\n", str);
+ } else
+ fprintf(stderr, "Error %s: %s\n", path, error);
+
+ g_free(user_data);
+
+ return 0;
+}
+
+static int cmd_remove_known_service(char *args[], int num, struct connman_option *options)
+{
+ char *path_of_service_to_remove;
+
+ if (num > 2)
+ return -E2BIG;
+
+ if (num < 2)
+ return -EINVAL;
+
+ if (check_dbus_name(args[1]) == false)
+ return -EINVAL;
+
+ path_of_service_to_remove = g_strdup_printf("%s", args[1]);
+
+ return __connmanctl_dbus_method_call(connection,
+ CONNMAN_SERVICE, CONNMAN_PATH,
+ "net.connman.Manager",
+ "RemoveKnownService",
+ remove_known_service_return, path_of_service_to_remove, NULL, NULL);
+}
+
static int cmd_peers(char *args[], int num, struct connman_option *options)
{
char *peer_name = NULL;
@@ -2738,6 +2790,10 @@ static const struct {
lookup_tether },
{ "services", "[<service>]", service_options, cmd_services,
"Display services", lookup_service_arg },
+ { "known-services", NULL, NULL, cmd_known_services,
+ "Display known services", NULL },
+ { "remove-known-service", "<service>", NULL,
+ cmd_remove_known_service, "Remove known service", NULL },
{ "peers", "[peer]", NULL, cmd_peers,
"Display peers", lookup_peer_arg },
{ "scan", "<technology>", NULL, cmd_scan,
diff --git a/src/connman.h b/src/connman.h
index 82e77d3..bb01385 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -665,6 +665,7 @@ int __connman_service_init(void);
void __connman_service_cleanup(void);
int __connman_service_load_modifiable(struct connman_service *service);
+void __connman_known_service_list_struct(DBusMessageIter *iter);
void __connman_service_list_struct(DBusMessageIter *iter);
int __connman_service_compare(const struct connman_service *a,
@@ -739,6 +740,7 @@ int __connman_service_disconnect_all(void);
void __connman_service_set_active_session(bool enable, GSList *list);
void __connman_service_auto_connect(enum connman_service_connect_reason reason);
bool __connman_service_remove(struct connman_service *service);
+bool __connman_service_remove_known_service(const char *path);
bool __connman_service_is_provider_pending(struct connman_service *service);
void __connman_service_set_provider_pending(struct connman_service *service,
DBusMessage *msg);
diff --git a/src/manager.c b/src/manager.c
index d15ce20..7c6ff14 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -175,6 +175,11 @@ static struct connman_notifier technology_notifier = {
.idle_state = idle_state,
};
+static void append_known_service_structs(DBusMessageIter *iter, void *user_data)
+{
+ __connman_known_service_list_struct(iter);
+}
+
static void append_service_structs(DBusMessageIter *iter, void *user_data)
{
__connman_service_list_struct(iter);
@@ -195,6 +200,58 @@ static DBusMessage *get_services(DBusConnection *conn,
return reply;
}
+static DBusMessage *get_known_services(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ __connman_dbus_append_objpath_dict_array(reply,
+ append_known_service_structs, NULL);
+
+ return reply;
+}
+
+static DBusMessage *remove_known_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ const char *path;
+ int err;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ /* get path */
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ /* extract service */
+ char *str = strrchr(path, '/');
+ if(NULL == str)
+ {
+ return __connman_error_failed(msg, -ENOENT);
+ }
+ str++;
+ if(0 >= strlen(str))
+ {
+ return __connman_error_failed(msg, -ENOENT);
+ }
+
+ DBG("Service to remove [%s]", str);
+
+ if (!__connman_service_remove_known_service(str))
+ {
+ return __connman_error_failed(msg, -ENOENT);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
static void append_peer_structs(DBusMessageIter *iter, void *user_data)
{
__connman_peer_list_struct(iter);
@@ -513,6 +570,12 @@ static const GDBusMethodTable manager_methods[] = {
{ GDBUS_DEPRECATED_METHOD("RemoveProvider",
GDBUS_ARGS({ "provider", "o" }), NULL,
remove_provider) },
+ { GDBUS_METHOD("GetKnownServices",
+ NULL, GDBUS_ARGS({"knownServices", "a(oa{sv})" }),
+ get_known_services) },
+ { GDBUS_METHOD("RemoveKnownService",
+ GDBUS_ARGS({ "path", "o" }), NULL,
+ remove_known_service) },
{ GDBUS_METHOD("GetServices",
NULL, GDBUS_ARGS({ "services", "a(oa{sv})" }),
get_services) },
diff --git a/src/service.c b/src/service.c
index 733c072..5de7974 100644
--- a/src/service.c
+++ b/src/service.c
@@ -2577,6 +2577,79 @@ static void append_struct(gpointer value, gpointer user_data)
append_struct_service(iter, append_dict_properties, service);
}
+void __connman_known_service_list_struct(DBusMessageIter *iter)
+{
+ gchar **services = NULL;
+ gchar **serviceIDParts = NULL;
+ int i = 0;
+ struct connman_service *service = NULL;
+
+ DBG("listing known services");
+
+ services = connman_storage_get_services();
+ if (services == NULL)
+ return;
+
+ for (i = 0; i < g_strv_length(services); i++)
+ {
+ service = connman_service_create();
+ if (service == NULL)
+ {
+ connman_error("connman_service_create() allocation failed");
+ return ;
+ }
+ service->identifier = g_strdup(services[i]);
+ serviceIDParts = g_strsplit(services[i], "_",
+ -1);
+ if (serviceIDParts != NULL)
+ {
+ service->type =
+ __connman_service_string2type(serviceIDParts[0]);
+ service->path =
+ g_strdup_printf("%s/service/%s", CONNMAN_PATH, service->identifier);
+ if (service->type ==
+ CONNMAN_SERVICE_TYPE_WIFI)
+ service->security =
+ __connman_service_string2security(serviceIDParts[g_strv_length(serviceIDParts) - 1]);
+
+ if (service->path != NULL)
+ {
+
+ if (find_service(service->path) != NULL)
+
+ service->state = (find_service(service->path))->state;
+ if (service->type ==
+ CONNMAN_SERVICE_TYPE_ETHERNET &&
+ find_service(service->path) != NULL)
+
+ service->name = (find_service(service->path))->name;
+
+ if (0 !=
+ service_load(service))
+ {
+
+ connman_error("service_load() returned error");
+
+ g_free(service);
+
+ g_strfreev(serviceIDParts);
+
+ g_strfreev(services);
+ return;
+ }
+
+ append_struct_service(iter,
+ append_dict_properties, service);
+ }
+
+ g_strfreev(serviceIDParts);
+ }
+ g_free(service);
+ }
+
+ g_strfreev(services);
+}
+
void __connman_service_list_struct(DBusMessageIter *iter)
{
g_list_foreach(service_list, append_struct, iter);
@@ -4406,6 +4479,13 @@ bool __connman_service_remove(struct connman_service *service)
return true;
}
+bool __connman_service_remove_known_service(const char *path)
+{
+ DBG("Remove known service [%s]", path);
+
+ return __connman_storage_remove_service(path);
+}
+
static DBusMessage *remove_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
diff --git a/tools/manager-api.c b/tools/manager-api.c
index e082962..b1291c6 100644
--- a/tools/manager-api.c
+++ b/tools/manager-api.c
@@ -64,6 +64,90 @@ static DBusMessage *set_property(DBusConnection *connection,
return reply;
}
+DBusMessage *manager_get_known_services(DBusConnection *connection)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ message = dbus_message_new_method_call(CONNMAN_SERVICE,
+ CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE,
+ "GetKnownServices");
+
+ if (!message)
+ return NULL;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+ if (!reply)
+ {
+ if (dbus_error_is_set(&error))
+ {
+ LOG("%s", error.message);
+ dbus_error_free(&error);
+ }
+ else
+ {
+ LOG("Failed to get known services");
+ }
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+
+ return reply;
+}
+
+DBusMessage *manager_remove_known_service(DBusConnection *connection,
+ const char *service_path)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ DBusMessageIter array;
+
+ DBG("Service path to remove [%s]", service_path);
+
+ message = dbus_message_new_method_call(CONNMAN_SERVICE,
+ CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE,
+ "RemoveKnownService");
+
+ if (!message)
+ return NULL;
+
+ dbus_error_init(&error);
+
+ dbus_message_iter_init_append(message, &array);
+
+ dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
+ &service_path);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+
+ if (!reply)
+ {
+ if (dbus_error_is_set(&error))
+ {
+ LOG("%s", error.message);
+ dbus_error_free(&error);
+ }
+ else
+ {
+ LOG("Failed to get known services");
+ }
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_message_unref(message);
+
+ return reply;
+}
+
DBusMessage *manager_get_services(DBusConnection *connection)
{
DBusMessage *message, *reply;
--
2.7.4
2 years
[PATCH] gdbus: Replace snprintf() with g_strdup_printf()
by Daniel Wagner
snprintf returns the number of characters that would have been written
if n had been sufficiently large. If the format string is longer than
the (size - offset), the snprintf will return a value larger than
the (size-offset). In normal cases,
DBUS_MAXIMUM_MATCH_RULE_LENGTH(1024) is large, but an attacker can
make malicious, large-scale inputs.
Note, g_strdup() and g_strdup_printf() will call abort if no memory
can't be allocated. Therefore we don't need to check for NULL
pointers.
Reported by jybarnes21
---
gdbus/watch.c | 65 ++++++++++++++++++++++++++++++++++-----------------
1 file changed, 43 insertions(+), 22 deletions(-)
diff --git a/gdbus/watch.c b/gdbus/watch.c
index 447e4867198e..8fa76cdaf8df 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -136,38 +136,55 @@ static struct filter_data *filter_data_find(DBusConnection *connection)
return NULL;
}
-static void format_rule(struct filter_data *data, char *rule, size_t size)
+static char *format_rule(struct filter_data *data)
{
+ char *rule, *tmp;
const char *sender;
- int offset;
- offset = snprintf(rule, size, "type='signal'");
+ rule = g_strdup("type='signal'");
sender = data->name ? : data->owner;
- if (sender)
- offset += snprintf(rule + offset, size - offset,
- ",sender='%s'", sender);
- if (data->path)
- offset += snprintf(rule + offset, size - offset,
- ",path='%s'", data->path);
- if (data->interface)
- offset += snprintf(rule + offset, size - offset,
- ",interface='%s'", data->interface);
- if (data->member)
- offset += snprintf(rule + offset, size - offset,
- ",member='%s'", data->member);
- if (data->argument)
- snprintf(rule + offset, size - offset,
- ",arg0='%s'", data->argument);
+ if (sender) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,sender='%s'", rule, sender);
+ g_free(tmp);
+ }
+
+ if (data->path) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,path='%s'", rule, data->path);
+ g_free(tmp);
+ }
+
+ if (data->interface){
+ tmp = rule;
+ rule = g_strdup_printf("%s,interface='%s'", rule,
+ data->interface);
+ g_free(tmp);
+ }
+
+ if (data->member) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,member='%s'", rule, data->member);
+ g_free(tmp);
+ }
+
+ if (data->argument) {
+ tmp = rule;
+ rule = g_strdup_printf("%s,arg0='%s'", rule, data->argument);
+ g_free(tmp);
+ }
+
+ return rule;
}
static gboolean add_match(struct filter_data *data,
DBusHandleMessageFunction filter)
{
DBusError err;
- char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+ char *rule;
- format_rule(data, rule, sizeof(rule));
+ rule = format_rule(data);
dbus_error_init(&err);
dbus_bus_add_match(data->connection, rule, &err);
@@ -175,21 +192,23 @@ static gboolean add_match(struct filter_data *data,
error("Adding match rule \"%s\" failed: %s", rule,
err.message);
dbus_error_free(&err);
+ g_free(rule);
return FALSE;
}
data->handle_func = filter;
data->registered = TRUE;
+ g_free(rule);
return TRUE;
}
static gboolean remove_match(struct filter_data *data)
{
DBusError err;
- char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+ char *rule;
- format_rule(data, rule, sizeof(rule));
+ rule = format_rule(data);
dbus_error_init(&err);
@@ -198,9 +217,11 @@ static gboolean remove_match(struct filter_data *data)
error("Removing owner match rule for %s failed: %s",
rule, err.message);
dbus_error_free(&err);
+ g_free(rule);
return FALSE;
}
+ g_free(rule);
return TRUE;
}
--
2.26.2
2 years, 1 month
[PATCH] util: Fixed implicit declaration of function 'strlen'
by Slava Monich
According to the man page #include <string.h> is required.
---
src/shared/util.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/shared/util.c b/src/shared/util.c
index 73c24ae..bda2d2b 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
+#include <string.h>
#include "src/shared/util.h"
--
1.9.1
2 years, 1 month