All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Zaborowski <andrew.zaborowski@intel.com>
To: iwd@lists.01.org
Subject: [PATCH 05/11] ap: Dump addreses in use and assign local IP
Date: Mon, 10 May 2021 10:58:00 +0200	[thread overview]
Message-ID: <20210510085806.174213-5-andrew.zaborowski@intel.com> (raw)
In-Reply-To: <20210510085806.174213-1-andrew.zaborowski@intel.com>

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

During AP start dump addresses in use by all netdevs, then handle the
local and global subnet address settings to select the final subnet and
IP and set that on the interface if not already set.

Restore the IP cleanup after stopping AP, removed temporarily in an
earlier commit.
---
 src/ap.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 178 insertions(+), 4 deletions(-)

diff --git a/src/ap.c b/src/ap.c
index 872c0a1f..37b71a6f 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -89,12 +89,16 @@ struct ap_state {
 	struct l_queue *sta_states;
 
 	struct l_dhcp_server *netconfig_dhcp;
+	uint32_t netconfig_addr4;
 	uint8_t netconfig_prefix_len4;
 	char **netconfig_addr4_str_list;
+	struct l_queue *netconfig_addr4_dump;
 	uint32_t rtnl_add_cmd;
+	uint32_t rtnl_dump_cmd;
 
 	bool started : 1;
 	bool gtk_set : 1;
+	bool cleanup_addr4 : 1;
 	bool enable_netconfig4 : 1;
 };
 
@@ -205,6 +209,13 @@ static void ap_reset(struct ap_state *ap)
 	if (ap->rtnl_add_cmd)
 		l_netlink_cancel(rtnl, ap->rtnl_add_cmd);
 
+	if (ap->rtnl_dump_cmd) {
+		uint32_t cmd = ap->rtnl_dump_cmd;
+
+		ap->rtnl_dump_cmd = 0;
+		l_netlink_cancel(rtnl, cmd);
+	}
+
 	l_queue_destroy(ap->sta_states, ap_sta_free);
 
 	if (ap->rates)
@@ -215,10 +226,29 @@ static void ap_reset(struct ap_state *ap)
 	ap->started = false;
 
 	/* Delete IP if one was set by IWD */
+	if (ap->cleanup_addr4) {
+		struct in_addr ia;
+		char ip_str[16];
+		uint32_t broadcast = ap->netconfig_addr4 |
+			~util_netmask_from_prefix(ap->netconfig_prefix_len4);
+		char broadcast_str[16];
+
+		ia.s_addr = htonl(ap->netconfig_addr4);
+		strcpy(ip_str, inet_ntoa(ia));
+		ia.s_addr = htonl(broadcast);
+		strcpy(broadcast_str, inet_ntoa(ia));
+
+		l_rtnl_ifaddr4_delete(rtnl, netdev_get_ifindex(netdev),
+					ap->netconfig_prefix_len4, ip_str,
+					broadcast_str, NULL, NULL, NULL);
+		ap->cleanup_addr4 = false;
+	}
 
 	if (ap->netconfig_dhcp)
 		l_dhcp_server_stop(ap->netconfig_dhcp);
 
+	l_queue_destroy(ap->netconfig_addr4_dump, l_free);
+	ap->netconfig_addr4_dump = NULL;
 	l_strv_free(ap->netconfig_addr4_str_list);
 	ap->netconfig_addr4_str_list = NULL;
 }
@@ -2047,9 +2077,20 @@ static void ap_start_cb(struct l_genl_msg *msg, void *user_data)
 		goto failed;
 	}
 
-	if (ap->netconfig_dhcp && !l_dhcp_server_start(ap->netconfig_dhcp)) {
-		l_error("DHCP server failed to start");
-		goto failed;
+	if (ap->netconfig_dhcp) {
+		/*
+		 * l_dhcp_server_start() would retrieve the current IPv4 from
+		 * the interface but set it anyway in case there are multiple
+		 * addresses, saves one ioctl too.
+		 */
+		struct in_addr ia = { .s_addr = htonl(ap->netconfig_addr4) };
+
+		if (!l_dhcp_server_set_ip_address(ap->netconfig_dhcp,
+							inet_ntoa(ia)) ||
+				!l_dhcp_server_start(ap->netconfig_dhcp)) {
+			l_error("DHCP server failed to start");
+			goto failed;
+		}
 	}
 
 	ap->started = true;
@@ -2737,6 +2778,130 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
 	return 0;
 }
 
+static void ap_netconfig_start(struct ap_state *ap)
+{
+	uint32_t ifindex = netdev_get_ifindex(ap->netdev);
+	int ret;
+	struct in_addr ia;
+	char addr4_str[16];
+	char broadcast4_str[16];
+	uint32_t new_addr4;
+
+	/*
+	 * The address pool specified for this AP (if any) has the priority,
+	 * next is the address currently set on the interface (if any) and
+	 * last is the global AP address pool (APAddressPool setting).
+	 */
+	if (ap->netconfig_addr4_str_list)
+		ret = ap_select_addr4((const char **)
+					ap->netconfig_addr4_str_list,
+					ap->netconfig_prefix_len4,
+					ap->netconfig_addr4_dump, &new_addr4);
+	else if (ap->netconfig_addr4)
+		goto already_set;
+	else
+		ret = ap_select_addr4((const char **) global_addr_strs,
+					ap->netconfig_prefix_len4,
+					ap->netconfig_addr4_dump, &new_addr4);
+
+	if (ret)
+		goto error;
+
+	/* See if the selected subnet is already set on the interface */
+	if (new_addr4 == ap->netconfig_addr4) {
+already_set:
+		/* Selected address already set, continue normally */
+		ap->cleanup_addr4 = false;
+
+		if (!ap_start_send(ap))
+			goto error;
+
+		goto cleanup;
+	}
+
+	ap->netconfig_addr4 = new_addr4;
+	ia.s_addr = htonl(ap->netconfig_addr4);
+	strcpy(addr4_str, inet_ntoa(ia));
+	ia.s_addr = htonl(ap->netconfig_addr4 |
+			~util_netmask_from_prefix(ap->netconfig_prefix_len4));
+	strcpy(broadcast4_str, inet_ntoa(ia));
+
+	ap->rtnl_add_cmd = l_rtnl_ifaddr4_add(rtnl, ifindex,
+						ap->netconfig_prefix_len4,
+						addr4_str, broadcast4_str,
+						ap_ifaddr4_added_cb, ap, NULL);
+	if (!ap->rtnl_add_cmd) {
+		l_error("Failed to add the IPv4 address");
+		goto error;
+	}
+
+	ap->cleanup_addr4 = true;
+
+cleanup:
+	l_queue_destroy(ap->netconfig_addr4_dump, l_free);
+	ap->netconfig_addr4_dump = NULL;
+	l_strv_free(ap->netconfig_addr4_str_list);
+	ap->netconfig_addr4_str_list = NULL;
+	return;
+
+error:
+	ap_start_failed(ap);
+}
+
+static void ap_ifaddr4_dump_cb(int error,
+				uint16_t type, const void *data,
+				uint32_t len, void *user_data)
+{
+	struct ap_state *ap = user_data;
+	const struct ifaddrmsg *ifa = data;
+	char *ip_str;
+	struct in_addr ia;
+	struct ap_rtnl_addr4_record *addr;
+
+	if (error) {
+		l_error("Error getting existing IPv4 addresses on AP iface");
+		return;
+	}
+
+	if (type != RTM_NEWADDR || ifa->ifa_prefixlen < 1)
+		return;
+
+	l_rtnl_ifaddr4_extract(ifa, len, NULL, &ip_str, NULL);
+	inet_aton(ip_str, &ia);
+	l_free(ip_str);
+
+	/*
+	 * Don't add current subnets from the target interface to the used
+	 * subnet address list because we'll be replacing them (or adding
+	 * another secondary address) so there won't be a routing conflict.
+	 */
+	if (ifa->ifa_index == netdev_get_ifindex(ap->netdev)) {
+		ap->netconfig_prefix_len4 = ifa->ifa_prefixlen;
+		ap->netconfig_addr4 = ntohl(ia.s_addr);
+		return;
+	}
+
+	addr = l_new(struct ap_rtnl_addr4_record, 1);
+	addr->prefix_len = ifa->ifa_prefixlen;
+	addr->addr = ntohl(ia.s_addr);
+
+	if (!ap->netconfig_addr4_dump)
+		ap->netconfig_addr4_dump = l_queue_new();
+
+	l_queue_push_tail(ap->netconfig_addr4_dump, addr);
+}
+
+static void ap_ifaddr4_dump_destroy_cb(void *user_data)
+{
+	struct ap_state *ap = user_data;
+
+	if (!ap->rtnl_dump_cmd)
+		return;
+
+	ap->rtnl_dump_cmd = 0;
+	ap_netconfig_start(ap);
+}
+
 /*
  * Start a simple independent WPA2 AP on given netdev.
  *
@@ -2832,7 +2997,16 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
 		l_error("Registering for MLME notification failed");
 
 	if (ap->enable_netconfig4) {
-		/* TODO: select an IP address, set it and call ap_start_send */
+		ap->rtnl_dump_cmd = l_rtnl_ifaddr4_dump(rtnl,
+						ap_ifaddr4_dump_cb, ap,
+						ap_ifaddr4_dump_destroy_cb);
+		if (!ap->rtnl_dump_cmd) {
+			if (err_out)
+				*err_out = -EIO;
+
+			l_error("Sending the IPv4 addr dump req failed");
+			goto error;
+		}
 
 		return ap;
 	}
-- 
2.27.0

  parent reply	other threads:[~2021-05-10  8:58 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-10  8:57 [PATCH 01/11] ap: Move sending CMD_START_AP to common function Andrew Zaborowski
2021-05-10  8:57 ` [PATCH 02/11] ap: Refactor DHCP settings loading Andrew Zaborowski
2021-05-11 14:56   ` Denis Kenzior
2021-05-10  8:57 ` [PATCH 03/11] ap: Refactor global address pool loading Andrew Zaborowski
2021-05-10  8:57 ` [PATCH 04/11] ap: Add subnet address selection logic Andrew Zaborowski
2021-05-11 15:06   ` Denis Kenzior
2021-05-11 21:04     ` Andrew Zaborowski
2021-05-11 22:20       ` Denis Kenzior
2021-05-10  8:58 ` Andrew Zaborowski [this message]
2021-05-10  8:58 ` [PATCH 06/11] ap: Move the DHCP server freeing to ap_reset Andrew Zaborowski
2021-05-10  8:58 ` [PATCH 07/11] ap: Send a specific error message on async AP start failure Andrew Zaborowski
2021-05-10  8:58 ` [PATCH 08/11] autotests: Update APRanges usage in testAP Andrew Zaborowski
2021-05-10  8:58 ` [PATCH 09/11] doc: Update AP settings in iwd.ap(5) and iwd.config(5) Andrew Zaborowski
2021-05-10  8:58 ` [PATCH 10/11] main: Add NetworkConfigurationEnabled to Daemon.GetInfo() Andrew Zaborowski
2021-05-11 15:09   ` Denis Kenzior
2021-05-10  8:58 ` [PATCH 11/11] doc: Document NetworkConfigurationEnabled in Daemon.GetInfo() Andrew Zaborowski
2021-05-11 14:48 ` [PATCH 01/11] ap: Move sending CMD_START_AP to common function Denis Kenzior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210510085806.174213-5-andrew.zaborowski@intel.com \
    --to=andrew.zaborowski@intel.com \
    --cc=iwd@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.