Wireless Daemon for Linux
 help / color / mirror / Atom feed
* [PATCH v2 1/2] netconfig: add ACD client for static configuration
@ 2020-12-10 21:22 James Prestwood
  2020-12-10 21:22 ` [PATCH v2 2/2] auto-t: add static netconfig test James Prestwood
  2020-12-10 22:20 ` [PATCH v2 1/2] netconfig: add ACD client for static configuration Denis Kenzior
  0 siblings, 2 replies; 3+ messages in thread
From: James Prestwood @ 2020-12-10 21:22 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 4556 bytes --]

When the IP is configured to be static we can now use ACD in
order to check that the IP is available and not already in
use. If a conflict is found netconfig will be reset and no IP
will be set on the interface. The ACD client is left with
the default 'defend once' policy, and probes are not turned
off. This will increase connection time, but for static IP's
it is the best approach.
---
 src/netconfig.c | 94 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 76 insertions(+), 18 deletions(-)

v2:
 * Added netconfig_reset_v4 to allow a failed ACD attempt to 
   reset only the IPv4 data.
 * Distinguish between CONFLICT/LOST events. For conflicts
   no IP was ever set in the kernel, so we can just clean up
   the rtnl address directly. For LOST events an address was
   set, so it would need to be deleted.

diff --git a/src/netconfig.c b/src/netconfig.c
index f48a789a..e7a6a402 100644
--- a/src/netconfig.c
+++ b/src/netconfig.c
@@ -64,6 +64,8 @@ struct netconfig {
 	void *user_data;
 
 	struct resolve *resolve;
+
+	struct l_acd *acd;
 };
 
 static struct l_netlink *rtnl;
@@ -804,15 +806,87 @@ static void netconfig_dhcp6_event_handler(struct l_dhcp6_client *client,
 	}
 }
 
+static void netconfig_reset_v4(struct netconfig *netconfig)
+{
+	if (netconfig->rtm_protocol) {
+		if (netconfig->v4_address) {
+			L_WARN_ON(!l_rtnl_ifaddr_delete(rtnl,
+						netconfig->ifindex,
+						netconfig->v4_address,
+						netconfig_ifaddr_del_cmd_cb,
+						netconfig, NULL));
+			l_rtnl_address_free(netconfig->v4_address);
+			netconfig->v4_address = NULL;
+		}
+
+		l_strfreev(netconfig->dns4_overrides);
+		netconfig->dns4_overrides = NULL;
+
+		l_dhcp_client_stop(netconfig->dhcp_client);
+		netconfig->rtm_protocol = 0;
+	}
+}
+
+static void netconfig_ipv4_acd_event(enum l_acd_event event, void *user_data)
+{
+	struct netconfig *netconfig = user_data;
+
+	switch (event) {
+	case L_ACD_EVENT_AVAILABLE:
+		L_WARN_ON(!l_rtnl_ifaddr_add(rtnl, netconfig->ifindex,
+					netconfig->v4_address,
+					netconfig_ipv4_ifaddr_add_cmd_cb,
+					netconfig, NULL));
+		return;
+	case L_ACD_EVENT_CONFLICT:
+		/*
+		 * Conflict found, no IP was actually set so just free/unset
+		 * anything we set prior to starting ACD.
+		 */
+		l_error("netconfig: statically configured address conflict!");
+		l_rtnl_address_free(netconfig->v4_address);
+		netconfig->v4_address = NULL;
+		netconfig->rtm_protocol = 0;
+		break;
+	case L_ACD_EVENT_LOST:
+		/*
+		 * Set IP but lost it some time after. Full (IPv4) reset in this
+		 * case.
+		 */
+		l_error("netconfig: statically configured address was lost");
+		netconfig_reset_v4(netconfig);
+		break;
+	}
+}
+
 static void netconfig_ipv4_select_and_install(struct netconfig *netconfig)
 {
 	netconfig->v4_address = netconfig_get_static4_address(netconfig);
 	if (netconfig->v4_address) {
+		char ip[INET6_ADDRSTRLEN];
+
 		netconfig->rtm_protocol = RTPROT_STATIC;
-		L_WARN_ON(!l_rtnl_ifaddr_add(rtnl, netconfig->ifindex,
+		netconfig->acd = l_acd_new(netconfig->ifindex);
+		l_acd_set_event_handler(netconfig->acd,
+					netconfig_ipv4_acd_event, netconfig,
+					NULL);
+		if (getenv("IWD_ACD_DEBUG"))
+			l_acd_set_debug(netconfig->acd, do_debug,
+					"[ACD] ", NULL);
+
+		l_rtnl_address_get_address(netconfig->v4_address, ip);
+
+		if (!l_acd_start(netconfig->acd, ip)) {
+			l_error("failed to start ACD, continuing anyways");
+			l_acd_destroy(netconfig->acd);
+			netconfig->acd = NULL;
+
+			L_WARN_ON(!l_rtnl_ifaddr_add(rtnl, netconfig->ifindex,
 					netconfig->v4_address,
 					netconfig_ipv4_ifaddr_add_cmd_cb,
 					netconfig, NULL));
+		}
+
 		return;
 	}
 
@@ -955,23 +1029,7 @@ bool netconfig_reset(struct netconfig *netconfig)
 	if (netconfig->rtm_protocol || netconfig->rtm_v6_protocol)
 		resolve_revert(netconfig->resolve);
 
-	if (netconfig->rtm_protocol) {
-		if (netconfig->v4_address) {
-			L_WARN_ON(!l_rtnl_ifaddr_delete(rtnl,
-						netconfig->ifindex,
-						netconfig->v4_address,
-						netconfig_ifaddr_del_cmd_cb,
-						netconfig, NULL));
-			l_rtnl_address_free(netconfig->v4_address);
-			netconfig->v4_address = NULL;
-		}
-
-		l_strfreev(netconfig->dns4_overrides);
-		netconfig->dns4_overrides = NULL;
-
-		l_dhcp_client_stop(netconfig->dhcp_client);
-		netconfig->rtm_protocol = 0;
-	}
+	netconfig_reset_v4(netconfig);
 
 	if (netconfig->rtm_v6_protocol) {
 		l_strfreev(netconfig->dns6_overrides);
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] auto-t: add static netconfig test
  2020-12-10 21:22 [PATCH v2 1/2] netconfig: add ACD client for static configuration James Prestwood
@ 2020-12-10 21:22 ` James Prestwood
  2020-12-10 22:20 ` [PATCH v2 1/2] netconfig: add ACD client for static configuration Denis Kenzior
  1 sibling, 0 replies; 3+ messages in thread
From: James Prestwood @ 2020-12-10 21:22 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 6657 bytes --]

Tests netconfig with a static configuration, as well as tests ACD
functionality.

The test has two IWD radios which will eventually use the same IP.
One is configured statically, one will receive the IP via DHCP.
The static client sets its IP first and begins using it. Then the
DHCP client is started. Since ACD in a DHCP client is configured
to use its address indefinitely, the static client *should* give
up its address.
---
 autotests/testNetconfig/connection_test.py   |  10 +-
 autotests/testNetconfig/hw.conf              |   7 +-
 autotests/testNetconfig/static_test.py       | 105 +++++++++++++++++++
 autotests/testNetconfig/storage/ssidTKIP.psk |   3 +
 4 files changed, 121 insertions(+), 4 deletions(-)
 create mode 100644 autotests/testNetconfig/static_test.py
 create mode 100644 autotests/testNetconfig/storage/ssidTKIP.psk

diff --git a/autotests/testNetconfig/connection_test.py b/autotests/testNetconfig/connection_test.py
index 5fc7a88e..caab090c 100644
--- a/autotests/testNetconfig/connection_test.py
+++ b/autotests/testNetconfig/connection_test.py
@@ -11,11 +11,12 @@ from iwd import NetworkType
 from hostapd import HostapdCLI
 import testutil
 from config import ctx
+import os
 
 class Test(unittest.TestCase):
 
     def test_connection_success(self):
-        wd = IWD()
+        wd = IWD(True)
 
         psk_agent = PSKAgent("secret123")
         wd.register_psk_agent(psk_agent)
@@ -62,12 +63,15 @@ class Test(unittest.TestCase):
         ctx.start_process(['ifconfig', hapd.ifname, '192.168.1.1', 'netmask', '255.255.255.0'],
                                 wait=True)
         ctx.start_process(['touch', '/tmp/dhcpd.leases'], wait=True)
-        ctx.start_process(['dhcpd', '-cf', '/tmp/dhcpd.conf', '-lf', '/tmp/dhcpd.leases',
-                            hapd.ifname])
+        cls.dhcpd_pid = ctx.start_process(['dhcpd', '-f', '-cf', '/tmp/dhcpd.conf',
+                                            '-lf', '/tmp/dhcpd.leases',
+                                            hapd.ifname])
 
     @classmethod
     def tearDownClass(cls):
         IWD.clear_storage()
+        cls.dhcpd_pid.kill()
+        os.system('rm -rf /tmp/dhcpd.leases')
 
 if __name__ == '__main__':
     unittest.main(exit=True)
diff --git a/autotests/testNetconfig/hw.conf b/autotests/testNetconfig/hw.conf
index 75c5ac6e..323f1fb2 100644
--- a/autotests/testNetconfig/hw.conf
+++ b/autotests/testNetconfig/hw.conf
@@ -1,6 +1,11 @@
 [SETUP]
-num_radios=2
+num_radios=3
 max_test_exec_interval_sec=40
+start_iwd=0
+hwsim_medium=no
 
 [HOSTAPD]
 rad0=ssidTKIP.conf
+
+[NameSpaces]
+ns0=rad2
diff --git a/autotests/testNetconfig/static_test.py b/autotests/testNetconfig/static_test.py
new file mode 100644
index 00000000..b304f06d
--- /dev/null
+++ b/autotests/testNetconfig/static_test.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python3
+
+import unittest
+import sys
+
+sys.path.append('../util')
+import iwd
+from iwd import IWD
+from iwd import PSKAgent
+from iwd import NetworkType
+from hostapd import HostapdCLI
+import testutil
+from config import ctx
+import os
+
+class Test(unittest.TestCase):
+
+    def test_connection_success(self):
+        wd = IWD(True, iwd_storage_dir='/tmp/storage')
+
+        ns0 = ctx.get_namespace('ns0')
+
+        wd_ns0 = IWD(True, namespace=ns0)
+
+        psk_agent = PSKAgent("secret123")
+        psk_agent_ns0 = PSKAgent("secret123", namespace=ns0)
+        wd.register_psk_agent(psk_agent)
+        wd_ns0.register_psk_agent(psk_agent_ns0)
+
+        dev1 = wd.list_devices(1)[0]
+        dev2 = wd_ns0.list_devices(1)[0]
+
+        condition = 'not obj.scanning'
+        wd.wait_for_object_condition(dev1, condition)
+
+        dev1.scan()
+
+        condition = 'not obj.scanning'
+        wd.wait_for_object_condition(dev1, condition)
+
+        ordered_network = dev1.get_ordered_network('ssidTKIP')
+
+        self.assertEqual(ordered_network.type, NetworkType.psk)
+
+        condition = 'not obj.connected'
+        wd.wait_for_object_condition(ordered_network.network_object, condition)
+
+        ordered_network.network_object.connect()
+
+        condition = 'obj.state == DeviceState.connected'
+        wd.wait_for_object_condition(dev1, condition)
+
+        testutil.test_iface_operstate()
+        testutil.test_ifaces_connected()
+
+        testutil.test_ip_address_match(dev1.name, '192.168.1.10')
+
+        dev2.scan()
+
+        condition = 'not obj.scanning'
+        wd_ns0.wait_for_object_condition(dev2, condition)
+
+        ordered_network = dev2.get_ordered_network('ssidTKIP', scan_if_needed=True)
+
+        condition = 'not obj.connected'
+        wd_ns0.wait_for_object_condition(ordered_network.network_object, condition)
+
+        ordered_network.network_object.connect()
+
+        condition = 'obj.state == DeviceState.connected'
+        wd_ns0.wait_for_object_condition(dev2, condition)
+
+        wd.wait(1)
+        testutil.test_ip_address_match(dev1.name, None)
+
+        dev1.disconnect()
+        dev2.disconnect()
+
+        condition = 'not obj.connected'
+        wd.wait_for_object_condition(ordered_network.network_object, condition)
+
+        wd.unregister_psk_agent(psk_agent)
+
+    @classmethod
+    def setUpClass(cls):
+        hapd = HostapdCLI()
+        # TODO: This could be moved into test-runner itself if other tests ever
+        #       require this functionality (p2p, FILS, etc.). Since its simple
+        #       enough it can stay here for now.
+        ctx.start_process(['ifconfig', hapd.ifname, '192.168.1.1', 'netmask', '255.255.255.0'],
+                                wait=True)
+        ctx.start_process(['touch', '/tmp/dhcpd.leases'], wait=True)
+        cls.dhcpd_pid = ctx.start_process(['dhcpd', '-f', '-cf', '/tmp/dhcpd.conf',
+                                            '-lf', '/tmp/dhcpd.leases',
+                                            hapd.ifname])
+        IWD.copy_to_storage('ssidTKIP.psk', '/tmp/storage')
+
+    @classmethod
+    def tearDownClass(cls):
+        IWD.clear_storage()
+        cls.dhcpd_pid.kill()
+        os.system('rm -rf /tmp/dhcpd.leases')
+
+if __name__ == '__main__':
+    unittest.main(exit=True)
diff --git a/autotests/testNetconfig/storage/ssidTKIP.psk b/autotests/testNetconfig/storage/ssidTKIP.psk
new file mode 100644
index 00000000..f15724a3
--- /dev/null
+++ b/autotests/testNetconfig/storage/ssidTKIP.psk
@@ -0,0 +1,3 @@
+[IPv4]
+Address=192.168.1.10
+Gateway=192.168.1.1
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2 1/2] netconfig: add ACD client for static configuration
  2020-12-10 21:22 [PATCH v2 1/2] netconfig: add ACD client for static configuration James Prestwood
  2020-12-10 21:22 ` [PATCH v2 2/2] auto-t: add static netconfig test James Prestwood
@ 2020-12-10 22:20 ` Denis Kenzior
  1 sibling, 0 replies; 3+ messages in thread
From: Denis Kenzior @ 2020-12-10 22:20 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 997 bytes --]

Hi James,

On 12/10/20 3:22 PM, James Prestwood wrote:
> When the IP is configured to be static we can now use ACD in
> order to check that the IP is available and not already in
> use. If a conflict is found netconfig will be reset and no IP
> will be set on the interface. The ACD client is left with
> the default 'defend once' policy, and probes are not turned
> off. This will increase connection time, but for static IP's
> it is the best approach.
> ---
>   src/netconfig.c | 94 +++++++++++++++++++++++++++++++++++++++----------
>   1 file changed, 76 insertions(+), 18 deletions(-)
> 
> v2:
>   * Added netconfig_reset_v4 to allow a failed ACD attempt to
>     reset only the IPv4 data.
>   * Distinguish between CONFLICT/LOST events. For conflicts
>     no IP was ever set in the kernel, so we can just clean up
>     the rtnl address directly. For LOST events an address was
>     set, so it would need to be deleted.
> 

Both applied, thanks

Regards,
-Denis

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-12-10 22:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-12-10 21:22 [PATCH v2 1/2] netconfig: add ACD client for static configuration James Prestwood
2020-12-10 21:22 ` [PATCH v2 2/2] auto-t: add static netconfig test James Prestwood
2020-12-10 22:20 ` [PATCH v2 1/2] netconfig: add ACD client for static configuration Denis Kenzior

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox