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 | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/service.c b/src/service.c index 1b95995..7885db2 100644 --- a/src/service.c +++ b/src/service.c @@ -4163,6 +4163,59 @@ done: __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4); } +/* + * How many networks are connected at the same time. If more than 1, + * then set the rp_filter setting properly (loose mode 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_rp_filter(struct connman_service *service, + gboolean connected) +{ + enum connman_ipconfig_method method; + + 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; + } + + if (connected == TRUE) { + if (connected_networks_count == 1) { + int filter_value; + filter_value = __connman_ipconfig_set_rp_filter(); + if (filter_value < 0) + return; + + original_rp_filter = filter_value; + } + connected_networks_count++; + + } else { + if (connected_networks_count == 2) + __connman_ipconfig_unset_rp_filter(original_rp_filter); + + connected_networks_count--; + if (connected_networks_count < 0) + connected_networks_count = 0; + } + + DBG("%s %s ipconfig %p method %d count %d filter %d", + connected ? "connected" : "disconnected", service->identifier, + service->ipconfig_ipv4, method, + connected_networks_count, original_rp_filter); +} + int __connman_service_ipconfig_indicate_state(struct connman_service *service, enum connman_service_state new_state, enum connman_ipconfig_type type) @@ -4208,9 +4261,10 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, case CONNMAN_SERVICE_STATE_READY: update_nameservers(service); - if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { check_proxy_setup(service); - else + service_rp_filter(service, TRUE); + } else __connman_wispr_start(service, type); break; case CONNMAN_SERVICE_STATE_ONLINE: @@ -4218,6 +4272,10 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, case CONNMAN_SERVICE_STATE_DISCONNECT: if (service->state == CONNMAN_SERVICE_STATE_IDLE) return -EINVAL; + + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + service_rp_filter(service, FALSE); + break; case CONNMAN_SERVICE_STATE_FAILURE: break; -- 1.7.1 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman