If more than one service is connected at the same time,
then activate loose mode routing by setting the
/proc/sys/net/ipv4/conf/all/rp_filter to value 2
If the loose mode routing is not activated, then packets
are not routed properly if services are connected to same
subnet.
The original value of rp_filter is restored when the other
services are disconnected and only one service is connected.
For details of rp_filter setting, see Linux kernel file
Documentation/networking/ip-sysctl.txt
Fixes BMC#23606
---
src/service.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 86 insertions(+), 0 deletions(-)
diff --git a/src/service.c b/src/service.c
index 1b95995..7cfeed5 100644
--- a/src/service.c
+++ b/src/service.c
@@ -5606,12 +5606,96 @@ void __connman_service_downgrade_state(struct
connman_service *service)
CONNMAN_IPCONFIG_TYPE_IPV6);
}
+/*
+ * How many networks are connected at the same time. If more than 1,
+ * then set the rp_filter setting properly (loose routing) so that network
+ * connectivity works ok. This is only done for IPv4 networks as IPv6
+ * does not have rp_filter knob.
+ */
+static int connected_networks_count;
+static int original_rp_filter;
+
+static void service_state_changed(struct connman_service *service,
+ enum connman_service_state state)
+{
+ enum connman_ipconfig_method method;
+
+ if (service->ipconfig_ipv4 == NULL)
+ return;
+
+ method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
+
+ switch (method) {
+ case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+ case CONNMAN_IPCONFIG_METHOD_OFF:
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ return;
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
+ case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ case CONNMAN_IPCONFIG_METHOD_DHCP:
+ break;
+ }
+
+ switch (state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ case CONNMAN_SERVICE_STATE_IDLE:
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ case CONNMAN_SERVICE_STATE_ONLINE:
+ return;
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ case CONNMAN_SERVICE_STATE_READY:
+ break;
+ }
+
+ if (state == CONNMAN_SERVICE_STATE_READY) {
+ /* We are connected */
+ if (connected_networks_count == 1) {
+ int filter_value;
+ filter_value = __connman_ipconfig_set_rp_filter(NULL);
+ if (filter_value < 0)
+ return;
+
+ original_rp_filter = filter_value;
+ }
+ connected_networks_count++;
+
+ } else {
+ /* We are disconnected */
+ if (connected_networks_count == 2)
+ __connman_ipconfig_unset_rp_filter(NULL,
+ original_rp_filter);
+
+ connected_networks_count--;
+ if (connected_networks_count < 0)
+ connected_networks_count = 0;
+ }
+
+ DBG("service %s ipconfig %p method %d state %d count %d filter %d",
+ service->identifier, service->ipconfig_ipv4, method,
+ service->state, connected_networks_count, original_rp_filter);
+}
+
+static struct connman_notifier service_notifier = {
+ .name = "service state changed",
+ .service_state_changed = service_state_changed,
+};
+
int __connman_service_init(void)
{
+ int err;
+
DBG("");
connection = connman_dbus_get_connection();
+ err = connman_notifier_register(&service_notifier);
+ if (err < 0) {
+ dbus_connection_unref(connection);
+ return err;
+ }
+
service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, NULL);
@@ -5626,6 +5710,8 @@ void __connman_service_cleanup(void)
DBG("");
+ connman_notifier_unregister(&service_notifier);
+
list = service_list;
service_list = NULL;
g_sequence_free(list);
--
1.7.1
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman