[PATCH v2] frame-xchg: fix invalid read
by James Prestwood
This seems to happen occationally with testAP (potentially others).
The invalid read appears to happen when the frame_xchg_tx_cb detects
an early status and no ACK. In this particular case there is no
retry interval so we reach the retry limit and 'done' the frame.
This frees the 'fx' data all before the destroy callback can get
called. Once we finally return and the destroy callback is called
'fx' is freed and we see the invalid write.
==206== Memcheck, a memory error detector
==206== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==206== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==206== Command: iwd -p rad1,rad2,rad3,rad4 -d
==206== Parent PID: 140
==206==
==206== Invalid write of size 4
==206== at 0x4493A0: frame_xchg_tx_destroy (frame-xchg.c:941)
==206== by 0x46DAF6: destroy_request (genl.c:673)
==206== by 0x46DAF6: process_unicast (genl.c:1002)
==206== by 0x46DAF6: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206== by 0x403E78: main (main.c:490)
==206== Address 0x4c59c6c is 172 bytes inside a block of size 176 free'd
==206== at 0x483B9F5: free (vg_replace_malloc.c:538)
==206== by 0x40F14C: destroy_work (wiphy.c:248)
==206== by 0x40F14C: wiphy_radio_work_done (wiphy.c:1578)
==206== by 0x44A916: frame_xchg_tx_cb (frame-xchg.c:930)
==206== by 0x46DAD9: process_unicast (genl.c:993)
==206== by 0x46DAD9: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206== by 0x403E78: main (main.c:490)
==206== Block was alloc'd at
==206== at 0x483A809: malloc (vg_replace_malloc.c:307)
==206== by 0x4643CD: l_malloc (util.c:61)
==206== by 0x44AF8C: frame_xchg_startv (frame-xchg.c:1155)
==206== by 0x44B2A4: frame_xchg_start (frame-xchg.c:1108)
==206== by 0x42BC55: ap_send_mgmt_frame (ap.c:709)
==206== by 0x42F513: ap_probe_req_cb (ap.c:1869)
==206== by 0x449752: frame_watch_unicast_notify (frame-xchg.c:233)
==206== by 0x46DA2F: dispatch_unicast_watches (genl.c:961)
==206== by 0x46DA2F: process_unicast (genl.c:980)
==206== by 0x46DA2F: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206==
---
src/frame-xchg.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
v2:
* Set fx->tx_cmd_id to zero after canceling
diff --git a/src/frame-xchg.c b/src/frame-xchg.c
index 0e3e330d..b4e092b8 100644
--- a/src/frame-xchg.c
+++ b/src/frame-xchg.c
@@ -773,8 +773,10 @@ static void frame_xchg_reset(struct frame_xchg_data *fx)
if (fx->timeout)
l_timeout_remove(fx->timeout);
- if (fx->tx_cmd_id)
+ if (fx->tx_cmd_id) {
l_genl_family_cancel(nl80211, fx->tx_cmd_id);
+ fx->tx_cmd_id = 0;
+ }
l_free(fx->early_frame.mpdu);
fx->early_frame.mpdu = NULL;
@@ -901,6 +903,8 @@ static void frame_xchg_tx_cb(struct l_genl_msg *msg, void *user_data)
uint64_t cookie;
bool early_status;
+ fx->tx_cmd_id = 0;
+
l_debug("err %i", -error);
if (error < 0) {
@@ -934,13 +938,6 @@ error:
frame_xchg_done(fx, error);
}
-static void frame_xchg_tx_destroy(void *user_data)
-{
- struct frame_xchg_data *fx = user_data;
-
- fx->tx_cmd_id = 0;
-}
-
static bool frame_xchg_tx_retry(struct wiphy_radio_work_item *item)
{
struct frame_xchg_data *fx = l_container_of(item,
@@ -974,7 +971,7 @@ static bool frame_xchg_tx_retry(struct wiphy_radio_work_item *item)
&duration);
fx->tx_cmd_id = l_genl_family_send(nl80211, msg, frame_xchg_tx_cb, fx,
- frame_xchg_tx_destroy);
+ NULL);
if (!fx->tx_cmd_id) {
l_error("Error sending frame");
l_genl_msg_unref(msg);
--
2.26.2
2 months, 3 weeks
[PATCH] resolve: allow setting default DNS resolver at compile time
by John Zimmermann
---
configure.ac | 15 +++++++++++++++
src/resolve.c | 4 ++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 78db15e9..0adddd10 100644
--- a/configure.ac
+++ b/configure.ac
@@ -250,6 +250,21 @@ if (test "${enable_systemd_service}" != "no" && test -z "${path_systemd_modloadd
fi
AC_SUBST(SYSTEMD_MODLOADDIR, [${path_systemd_modloaddir}])
+AC_ARG_WITH(resolver, AC_HELP_STRING([--with-resolver=(systemd|resolvconf)],
+ [Set default DNS resolver [default=systemd]]),,
+ [with_resolver=systemd])
+
+case "x$with_resolver" in
+ "xsystemd")
+ AC_DEFINE(DEFAULT_RESOLVER, "systemd", ["Default DNS resolver"])
+ ;;
+ "xresolvconf")
+ AC_DEFINE(DEFAULT_RESOLVER, "resolvconf", ["Default DNS resolver"])
+ ;;
+ *) AC_MSG_ERROR([Wrong value for --with-resolver: $with_resolver])
+ ;;
+esac
+
AC_ARG_ENABLE([external_ell], AC_HELP_STRING([--enable-external-ell],
[enable external Embedded Linux library]),
[enable_external_ell=${enableval}])
diff --git a/src/resolve.c b/src/resolve.c
index 066e4c87..8949edad 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -553,8 +553,8 @@ static int resolve_init(void)
if (method_name)
l_warn("[General].dns_resolve_method is deprecated, "
"use [Network].NameResolvingService");
- else /* Default to systemd-resolved service. */
- method_name = "systemd";
+ else /* Default to compile time option (default: systemd-resolved) */
+ method_name = DEFAULT_RESOLVER;
}
for (i = 0; resolve_method_ops_list[i].name; i++) {
--
2.29.0
2 months, 3 weeks
[PATCH 1/5] storage: add storage_network_filename_from_path
by James Prestwood
This is to allow this API to be used simply to get the file name
without extension. AP will be storing provisioning files similarly
to the network format but the extension will not map to existing
security types. Some of the parsing code from
storage_network_ssid_from_path was reused for parsing the file name
and verification.
---
src/storage.c | 40 ++++++++++++++++++++++++++++++++++------
src/storage.h | 1 +
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/src/storage.c b/src/storage.c
index 00d93933..60fb1bc3 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -287,13 +287,12 @@ char *storage_get_network_file_path(enum security type, const char *ssid)
return path;
}
-const char *storage_network_ssid_from_path(const char *path,
- enum security *type)
+static bool parse_file_path(const char *path, char *buf,
+ const char **ext_offset)
{
const char *filename = strrchr(path, '/');
const char *c, *end;
char *decoded;
- static char buf[67];
if (filename)
filename++; /* Skip the / */
@@ -302,8 +301,8 @@ const char *storage_network_ssid_from_path(const char *path,
end = strchr(filename, '.');
- if (!end || !security_from_str(end + 1, type))
- return NULL;
+ if (!end)
+ return false;
if (filename[0] != '=') {
if (end == filename || end - filename > 32)
@@ -319,7 +318,7 @@ const char *storage_network_ssid_from_path(const char *path,
memcpy(buf, filename, end - filename);
buf[end - filename] = '\0';
- return buf;
+ goto done;
}
if (end - filename <= 1 || end - filename > 65)
@@ -342,6 +341,35 @@ const char *storage_network_ssid_from_path(const char *path,
strcpy(buf, decoded);
l_free(decoded);
+done:
+ if (ext_offset)
+ *ext_offset = end;
+
+ return true;
+}
+
+const char *storage_network_filename_from_path(const char *path)
+{
+ static char buf[67];
+
+ if (!parse_file_path(path, buf, NULL))
+ return NULL;
+
+ return buf;
+}
+
+const char *storage_network_ssid_from_path(const char *path,
+ enum security *type)
+{
+ const char *end;
+ static char buf[67];
+
+ if (!parse_file_path(path, buf, &end))
+ return NULL;
+
+ if (!security_from_str(end + 1, type))
+ return NULL;
+
return buf;
}
diff --git a/src/storage.h b/src/storage.h
index 80b63c53..d9b17c7f 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -37,6 +37,7 @@ void storage_cleanup_dirs(void);
char *storage_get_path(const char *format, ...);
char *storage_get_hotspot_path(const char *format, ...);
+const char *storage_network_filename_from_path(const char *path);
const char *storage_network_ssid_from_path(const char *path,
enum security *type);
char *storage_get_network_file_path(enum security type, const char *ssid);
--
2.26.2
2 months, 3 weeks
[PATCH] auto-t: fix hotspot autoconnect test
by James Prestwood
The test was removing files in /var/lib/iwd which is no longer
mounted read/write (nor are config files put there anymore).
---
autotests/testHotspot/autoconnect_test.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/autotests/testHotspot/autoconnect_test.py b/autotests/testHotspot/autoconnect_test.py
index 252a4b92..b8caa7fb 100644
--- a/autotests/testHotspot/autoconnect_test.py
+++ b/autotests/testHotspot/autoconnect_test.py
@@ -47,7 +47,7 @@ class Test(unittest.TestCase):
#
# Remove provisioning file, this should cause a disconnect.
#
- os.remove("/var/lib/iwd/ssidWPA2-1.psk")
+ os.remove("/tmp/iwd/ssidWPA2-1.psk")
condition = 'obj.state == DeviceState.disconnected'
wd.wait_for_object_condition(device, condition)
@@ -74,7 +74,7 @@ class Test(unittest.TestCase):
testutil.test_iface_operstate()
testutil.test_ifaces_connected(device.name, hapd_hotspot.ifname)
- os.remove('/var/lib/iwd/hotspot/autoconnect.conf')
+ os.remove('/tmp/iwd/hotspot/autoconnect.conf')
#
# make sure removal of hotspot conf file resulted in disconnect
--
2.26.2
2 months, 3 weeks
[PATCH] frame-xchg: fix invalid read
by James Prestwood
This seems to happen occationally with testAP (potentially others).
The invalid read appears to happen when the frame_xchg_tx_cb detects
an early status and no ACK. In this particular case there is no
retry interval so we reach the retry limit and 'done' the frame.
This frees the 'fx' data all before the destroy callback can get
called. Once we finally return and the destroy callback is called
'fx' is freed and we see the invalid write.
==206== Memcheck, a memory error detector
==206== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==206== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==206== Command: iwd -p rad1,rad2,rad3,rad4 -d
==206== Parent PID: 140
==206==
==206== Invalid write of size 4
==206== at 0x4493A0: frame_xchg_tx_destroy (frame-xchg.c:941)
==206== by 0x46DAF6: destroy_request (genl.c:673)
==206== by 0x46DAF6: process_unicast (genl.c:1002)
==206== by 0x46DAF6: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206== by 0x403E78: main (main.c:490)
==206== Address 0x4c59c6c is 172 bytes inside a block of size 176 free'd
==206== at 0x483B9F5: free (vg_replace_malloc.c:538)
==206== by 0x40F14C: destroy_work (wiphy.c:248)
==206== by 0x40F14C: wiphy_radio_work_done (wiphy.c:1578)
==206== by 0x44A916: frame_xchg_tx_cb (frame-xchg.c:930)
==206== by 0x46DAD9: process_unicast (genl.c:993)
==206== by 0x46DAD9: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206== by 0x403E78: main (main.c:490)
==206== Block was alloc'd at
==206== at 0x483A809: malloc (vg_replace_malloc.c:307)
==206== by 0x4643CD: l_malloc (util.c:61)
==206== by 0x44AF8C: frame_xchg_startv (frame-xchg.c:1155)
==206== by 0x44B2A4: frame_xchg_start (frame-xchg.c:1108)
==206== by 0x42BC55: ap_send_mgmt_frame (ap.c:709)
==206== by 0x42F513: ap_probe_req_cb (ap.c:1869)
==206== by 0x449752: frame_watch_unicast_notify (frame-xchg.c:233)
==206== by 0x46DA2F: dispatch_unicast_watches (genl.c:961)
==206== by 0x46DA2F: process_unicast (genl.c:980)
==206== by 0x46DA2F: received_data (genl.c:1101)
==206== by 0x46AA4B: io_callback (io.c:118)
==206== by 0x469D6C: l_main_iterate (main.c:477)
==206== by 0x469E1B: l_main_run (main.c:524)
==206== by 0x469E1B: l_main_run (main.c:506)
==206== by 0x46A02B: l_main_run_with_signal (main.c:646)
==206==
---
src/frame-xchg.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/src/frame-xchg.c b/src/frame-xchg.c
index 0e3e330d..21dfd706 100644
--- a/src/frame-xchg.c
+++ b/src/frame-xchg.c
@@ -901,6 +901,8 @@ static void frame_xchg_tx_cb(struct l_genl_msg *msg, void *user_data)
uint64_t cookie;
bool early_status;
+ fx->tx_cmd_id = 0;
+
l_debug("err %i", -error);
if (error < 0) {
@@ -934,13 +936,6 @@ error:
frame_xchg_done(fx, error);
}
-static void frame_xchg_tx_destroy(void *user_data)
-{
- struct frame_xchg_data *fx = user_data;
-
- fx->tx_cmd_id = 0;
-}
-
static bool frame_xchg_tx_retry(struct wiphy_radio_work_item *item)
{
struct frame_xchg_data *fx = l_container_of(item,
@@ -974,7 +969,7 @@ static bool frame_xchg_tx_retry(struct wiphy_radio_work_item *item)
&duration);
fx->tx_cmd_id = l_genl_family_send(nl80211, msg, frame_xchg_tx_cb, fx,
- frame_xchg_tx_destroy);
+ NULL);
if (!fx->tx_cmd_id) {
l_error("Error sending frame");
l_genl_msg_unref(msg);
--
2.26.2
2 months, 3 weeks
API recommendation?
by Bruce Johnson
Does anyone have recommendations for interacting with iwd programmatically? I'm trying to integrate a Python-based web back-end with iwd so that I can set up Wi-Fi client connections, report on available access points, etc. It's easy enough for me to shell out and use iwctl to set parameters, but its output is less than ideal for screen-scraping (which is admittedly a Bad Idea anyway). I've been looking to see if someone has put together an API, and I'm coming up empty. I would hate to try to reinvent the wheel, hence the question.
Thanks!
2 months, 3 weeks
[PATCH v6 1/3] ap: add support for DHCPv4 server
by James Prestwood
The DHCP server can be enabled by enabling network configuration
with [General].EnableNetworkConfiguration. If an IP is not set
on the interface before the AP is started a valid IP range must
also be provided under [General].APRanges in IP prefix format e.g.
[General]
EnableNetworkConfiguration=true
APRanges=192.168.1.1/24
Each AP started will get assigned a new subnet within the range
specified by APRanges as to not conflict with other AP interfaces.
If there are no subnets left in the pool when an AP is started
it will fail with -EEXIST. Any AP's that are stopped will release
their subnet back into the pool to be used with other APs.
The DHCP IP pool will be automatically chosen by the ELL DHCP
implementation (+1 the AP's IP to *.254). The remaining DHCP
settings will be defaults chosen by ELL (DNS, lease time, etc).
---
src/ap.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 275 insertions(+), 6 deletions(-)
v6:
- Restrict IP prefix to 24 or less
- Fix using netmask as the broadcast address when setting IP
- delete IP when AP resets
diff --git a/src/ap.c b/src/ap.c
index b10b65ae..b8f84512 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -26,6 +26,8 @@
#include <errno.h>
#include <linux/if_ether.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include <ell/ell.h>
@@ -74,6 +76,10 @@ struct ap_state {
uint16_t last_aid;
struct l_queue *sta_states;
+ struct l_dhcp_server *server;
+ uint32_t rtnl_add_cmd;
+ char *own_ip;
+
bool started : 1;
bool gtk_set : 1;
};
@@ -104,7 +110,115 @@ struct ap_wsc_pbc_probe_record {
uint64_t timestamp;
};
+struct ap_ip_pool {
+ uint32_t start;
+ uint32_t end;
+ uint8_t prefix;
+
+ /* Fist/last valid subnet */
+ uint8_t sub_start;
+ uint8_t sub_end;
+
+ struct l_uintset *used;
+};
+
+struct ap_ip_pool pool;
static uint32_t netdev_watch;
+struct l_netlink *rtnl;
+
+/*
+ * Creates pool of IPs which AP intefaces can use. Each call to ip_pool_get
+ * will advance the subnet +1 so there are no IP conflicts between AP
+ * interfaces
+ */
+static bool ip_pool_create(const char *ip_prefix)
+{
+ if (!util_ip_prefix_tohl(ip_prefix, &pool.prefix, &pool.start,
+ &pool.end, NULL))
+ return false;
+
+ if (pool.prefix > 24) {
+ l_error("APRanges prefix must 24 or less (%u used)",
+ pool.prefix);
+ memset(&pool, 0, sizeof(pool));
+ return false;
+ }
+
+ /*
+ * Find the number of subnets we can use, this will dictate the number
+ * of AP interfaces that can be created (when using DHCP)
+ */
+ pool.sub_start = (pool.start & 0x0000ff00) >> 8;
+ pool.sub_end = (pool.end & 0x0000ff00) >> 8;
+
+ pool.used = l_uintset_new_from_range(pool.sub_start, pool.sub_end);
+
+ return true;
+}
+
+static char *ip_pool_get()
+{
+ uint32_t ip;
+ struct in_addr ia;
+ uint8_t next_subnet = (uint8_t)l_uintset_find_unused_min(pool.used);
+
+ /* This shouldn't happen */
+ if (next_subnet < pool.sub_start || next_subnet > pool.sub_end)
+ return NULL;
+
+ l_uintset_put(pool.used, next_subnet);
+
+ ip = pool.start;
+ ip &= 0xffff00ff;
+ ip |= (next_subnet << 8);
+
+ ia.s_addr = htonl(ip);
+ return l_strdup(inet_ntoa(ia));
+}
+
+static bool ip_pool_put(const char *address)
+{
+ struct in_addr ia;
+ uint32_t ip;
+ uint8_t subnet;
+
+ if (inet_aton(address, &ia) < 0)
+ return false;
+
+ ip = ntohl(ia.s_addr);
+
+ subnet = (ip & 0x0000ff00) >> 8;
+
+ if (subnet < pool.sub_start || subnet > pool.sub_end)
+ return false;
+
+ return l_uintset_take(pool.used, subnet);
+}
+
+static void ip_pool_destroy()
+{
+ if (pool.used)
+ l_uintset_free(pool.used);
+
+ memset(&pool, 0, sizeof(pool));
+}
+
+static const char *broadcast_from_ip(const char *ip)
+{
+ struct in_addr ia;
+ uint32_t bcast;
+
+ if (inet_aton(ip, &ia) < 0)
+ return NULL;
+
+ bcast = ntohl(ia.s_addr);
+ bcast &= 0xffffff00;
+ bcast |= 0x000000ff;
+
+ ia.s_addr = htonl(bcast);
+
+ return inet_ntoa(ia);
+}
void ap_config_free(struct ap_config *config)
{
@@ -181,6 +295,9 @@ static void ap_reset(struct ap_state *ap)
if (ap->start_stop_cmd_id)
l_genl_family_cancel(ap->nl80211, ap->start_stop_cmd_id);
+ if (ap->rtnl_add_cmd)
+ l_netlink_cancel(rtnl, ap->rtnl_add_cmd);
+
l_queue_destroy(ap->sta_states, ap_sta_free);
if (ap->rates)
@@ -192,6 +309,19 @@ static void ap_reset(struct ap_state *ap)
l_queue_destroy(ap->wsc_pbc_probes, l_free);
ap->started = false;
+
+ if (ap->own_ip) {
+ l_rtnl_ifaddr4_delete(rtnl, netdev_get_ifindex(netdev),
+ pool.prefix, ap->own_ip,
+ broadcast_from_ip(ap->own_ip),
+ NULL, NULL, NULL);
+
+ ip_pool_put(ap->own_ip);
+ l_free(ap->own_ip);
+ }
+
+ if (ap->server)
+ l_dhcp_server_stop(ap->server);
}
static void ap_del_station(struct sta_state *sta, uint16_t reason,
@@ -1900,6 +2030,22 @@ static void ap_deauth_cb(const struct mmpdu_header *hdr, const void *body,
ap_sta_free(sta);
}
+static void do_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ l_info("%s%s", prefix, str);
+}
+
+static void ap_start_failed(struct ap_state *ap)
+{
+ ap->ops->handle_event(AP_EVENT_START_FAILED, NULL, ap->user_data);
+ ap_reset(ap);
+ l_genl_family_free(ap->nl80211);
+
+ l_free(ap);
+}
+
static void ap_start_cb(struct l_genl_msg *msg, void *user_data)
{
struct ap_state *ap = user_data;
@@ -1909,16 +2055,26 @@ static void ap_start_cb(struct l_genl_msg *msg, void *user_data)
if (l_genl_msg_get_error(msg) < 0) {
l_error("START_AP failed: %i", l_genl_msg_get_error(msg));
- ap->ops->handle_event(AP_EVENT_START_FAILED, NULL,
- ap->user_data);
- ap_reset(ap);
- l_genl_family_free(ap->nl80211);
- l_free(ap);
- return;
+ goto failed;
+ }
+
+ /*
+ * TODO: Add support for provisioning files where user could configure
+ * specific DHCP sever settings.
+ */
+
+ if (ap->server && !l_dhcp_server_start(ap->server)) {
+ l_error("DHCP server failed to start");
+ goto failed;
}
ap->started = true;
ap->ops->handle_event(AP_EVENT_STARTED, NULL, ap->user_data);
+
+ return;
+
+failed:
+ ap_start_failed(ap);
}
static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
@@ -1989,6 +2145,37 @@ static struct l_genl_msg *ap_build_cmd_start_ap(struct ap_state *ap)
return cmd;
}
+static void ap_ifaddr4_added_cb(int error, uint16_t type, const void *data,
+ uint32_t len, void *user_data)
+{
+ struct ap_state *ap = user_data;
+ struct l_genl_msg *cmd;
+
+ ap->rtnl_add_cmd = 0;
+
+ if (error) {
+ l_error("Failed to set IP address");
+ goto error;
+ }
+
+ cmd = ap_build_cmd_start_ap(ap);
+ if (!cmd)
+ goto error;
+
+ ap->start_stop_cmd_id = l_genl_family_send(ap->nl80211, cmd,
+ ap_start_cb, ap, NULL);
+ if (!ap->start_stop_cmd_id) {
+ l_genl_msg_unref(cmd);
+ goto error;
+ }
+
+ return;
+
+error:
+ ap_start_failed(ap);
+}
+
+
static void ap_mlme_notify(struct l_genl_msg *msg, void *user_data)
{
struct ap_state *ap = user_data;
@@ -2040,6 +2227,8 @@ struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
struct wiphy *wiphy = netdev_get_wiphy(netdev);
struct l_genl_msg *cmd;
uint64_t wdev_id = netdev_get_wdev_id(netdev);
+ uint32_t ifindex = netdev_get_ifindex(netdev);
+ struct in_addr ia;
int err = -EINVAL;
if (err_out)
@@ -2140,6 +2329,54 @@ struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
if (!ap->mlme_watch)
l_error("Registering for MLME notification failed");
+ /* No IP pool initialized, DHCP is not being used */
+ if (!pool.used)
+ goto done;
+
+ ap->server = l_dhcp_server_new(ifindex);
+ if (!ap->server) {
+ l_error("Failed to create DHCP server on %u", ifindex);
+ goto error;
+ }
+
+ if (getenv("IWD_DHCP_DEBUG"))
+ l_dhcp_server_set_debug(ap->server, do_debug,
+ "[DHCPv4 SERV] ", NULL);
+
+ /*
+ * If there is no IP set on the interface use one from the IP pool
+ * defined in main.conf.
+ */
+ if (!l_net_get_address(ifindex, &ia) || ia.s_addr == 0) {
+ ap->own_ip = ip_pool_get();
+
+ if (!ap->own_ip) {
+ l_error("No more IP's in pool, cannot start AP on %u",
+ ifindex);
+ err = -EEXIST;
+ goto error;
+ }
+
+ ap->rtnl_add_cmd = l_rtnl_ifaddr4_add(rtnl, ifindex,
+ pool.prefix, ap->own_ip,
+ broadcast_from_ip(ap->own_ip),
+ ap_ifaddr4_added_cb, ap, NULL);
+
+ if (!ap->rtnl_add_cmd) {
+ l_error("Failed to add IPv4 address");
+ goto error;
+ }
+
+
+ if (err_out)
+ *err_out = 0;
+
+ /* Finish starting AP in added callback */
+ return ap;
+ }
+ /* Else honor the IP set on the interface prior to calling Start() */
+
+done:
cmd = ap_build_cmd_start_ap(ap);
if (!cmd)
goto error;
@@ -2160,6 +2397,7 @@ error:
if (err_out)
*err_out = err;
+ ap->config = NULL;
ap_reset(ap);
l_genl_family_free(ap->nl80211);
l_free(ap);
@@ -2266,6 +2504,8 @@ void ap_free(struct ap_state *ap)
{
ap_reset(ap);
l_genl_family_free(ap->nl80211);
+ if (ap->server)
+ l_dhcp_server_destroy(ap->server);
l_free(ap);
}
@@ -2542,11 +2782,38 @@ static void ap_netdev_watch(struct netdev *netdev,
static int ap_init(void)
{
+ const struct l_settings *settings = iwd_get_config();
+ bool dhcp_enable = false;
+
netdev_watch = netdev_watch_add(ap_netdev_watch, NULL, NULL);
l_dbus_register_interface(dbus_get_bus(), IWD_AP_INTERFACE,
ap_setup_interface, ap_destroy_interface, false);
+ /*
+ * Reusing [General].EnableNetworkConfiguration as a switch to enable
+ * DHCP server. If no value is found or it is false do not create a
+ * DHCP server.
+ */
+ l_settings_get_bool(settings, "General", "EnableNetworkConfiguration",
+ &dhcp_enable);
+
+ if (dhcp_enable) {
+ L_AUTO_FREE_VAR(char *, ip_prefix);
+
+ ip_prefix = l_settings_get_string(settings, "General",
+ "APRanges");
+ if (!ip_prefix) {
+ l_error("[General].APRanges must be set for DHCP");
+ return -EINVAL;
+ }
+
+ if (!ip_pool_create(ip_prefix))
+ return -EINVAL;
+
+ rtnl = iwd_get_rtnl();
+ }
+
return 0;
}
@@ -2554,6 +2821,8 @@ static void ap_exit(void)
{
netdev_watch_remove(netdev_watch);
l_dbus_unregister_interface(dbus_get_bus(), IWD_AP_INTERFACE);
+
+ ip_pool_destroy();
}
IWD_MODULE(ap, ap_init, ap_exit)
--
2.26.2
2 months, 3 weeks
[PATCH] monitor: print survey info results
by Alvin Sipraga
Example output:
> Result: New Survey Results (0x33) len 76 [multi] 14.062327
Interface Index: 6 (0x00000006)
Survey Info: len 64
Frequency: 2472 (0x000009a8)
Noise dBm: -89
Survey Time: 100 (0x0000000000000064)
Busy Time: 4 (0x0000000000000004)
RX Time: 3 (0x0000000000000003)
TX Time: 0 (0x0000000000000000)
---
monitor/nlmon.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/monitor/nlmon.c b/monitor/nlmon.c
index b4578c85..7b2fb539 100644
--- a/monitor/nlmon.c
+++ b/monitor/nlmon.c
@@ -4915,6 +4915,19 @@ static const struct attr_entry frame_types_table[] = {
{ }
};
+static const struct attr_entry survey_info_table[] = {
+ { NL80211_SURVEY_INFO_FREQUENCY, "Frequency", ATTR_U32 },
+ { NL80211_SURVEY_INFO_NOISE, "Noise dBm", ATTR_S8 },
+ { NL80211_SURVEY_INFO_IN_USE, "Channel Currently In Use", ATTR_FLAG },
+ { NL80211_SURVEY_INFO_TIME, "Survey Time", ATTR_U64 },
+ { NL80211_SURVEY_INFO_TIME_BUSY, "Busy Time", ATTR_U64 },
+ { NL80211_SURVEY_INFO_TIME_EXT_BUSY, "Busy Time Extension Channel", ATTR_U64 },
+ { NL80211_SURVEY_INFO_TIME_RX, "RX Time", ATTR_U64 },
+ { NL80211_SURVEY_INFO_TIME_TX, "TX Time", ATTR_U64 },
+ { NL80211_SURVEY_INFO_TIME_SCAN, "Scan Time", ATTR_U64 },
+ { }
+};
+
static void print_cqm_event(unsigned int level, const char *label,
const void *data, uint16_t size)
{
@@ -5596,7 +5609,7 @@ static const struct attr_entry attr_table[] = {
{ NL80211_ATTR_4ADDR,
"4-Address", ATTR_U8 },
{ NL80211_ATTR_SURVEY_INFO,
- "Survey Info" },
+ "Survey Info", ATTR_NESTED, { survey_info_table } },
{ NL80211_ATTR_PMKID,
"PMKID", ATTR_BINARY },
{ NL80211_ATTR_MAX_NUM_PMKIDS,
--
2.29.0
2 months, 3 weeks
[PATCH 1/2] util: add util_ip_prefix_tohl
by James Prestwood
Parses an IP prefix notation string into prefix, start, end, and
netmask. All values are returned in host order.
---
src/util.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/util.h | 3 ++
2 files changed, 93 insertions(+)
- Moved these two into their own set
- Changed the loop to only iterate over the maximum IP string size (16).
This prevents looping through a really long (invalid) IP string
- Use l_strlcpy instead of memcpy + NULL terminate
diff --git a/src/util.c b/src/util.c
index 13b01c81..ac22b261 100644
--- a/src/util.c
+++ b/src/util.c
@@ -28,6 +28,8 @@
#include <stdio.h>
#include <sys/uio.h>
#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include <ell/ell.h>
@@ -218,3 +220,91 @@ const char *util_get_username(const char *identity)
return identity;
}
+
+static bool is_prefix_valid(uint32_t ip, unsigned int prefix)
+{
+ int i;
+
+ for (i = 31 - prefix; i >= 0; i--) {
+ if (ip & (1 << i))
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Parse a prefix notation IP string (e.g. A.B.C.D/E) into an IP range and
+ * netmask. All returned IP addresses/mask will be in host order. The start/end
+ * IP will only include the usable IP range where the last octet is not zero or
+ * 255.
+ */
+bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix_out,
+ uint32_t *start_out, uint32_t *end_out,
+ uint32_t *mask_out)
+{
+ struct in_addr ia;
+ int i;
+ unsigned int prefix = 0;
+ char no_prefix[INET_ADDRSTRLEN];
+ char *endp;
+ uint32_t start_ip;
+ uint32_t end_ip;
+ uint32_t netmask = 0xffffffff;
+
+ /*
+ * Only iterate over the max length of an IP in case of invalid long
+ * inputs.
+ */
+ for (i = 0; i < INET_ADDRSTRLEN && ip[i] != '\0'; i++) {
+ /* Found '/', check the next byte exists and parse prefix */
+ if (ip[i] == '/' && ip[i + 1] != '\0') {
+ prefix = strtol(ip + i + 1, &endp, 10);
+ if (*endp != '\0')
+ return false;
+
+ break;
+ }
+ }
+
+ if (prefix < 1 || prefix > 31)
+ return false;
+
+ /* 'i' will be at most INET_ADDRSTRLEN - 1 */
+ l_strlcpy(no_prefix, ip, i + 1);
+
+ /* Check if IP preceeding prefix is valid */
+ if (inet_pton(AF_INET, no_prefix, &ia) != 1 || ia.s_addr == 0)
+ return false;
+
+ start_ip = ntohl(ia.s_addr);
+
+ if (!is_prefix_valid(start_ip, prefix))
+ return false;
+
+ /* Usable range is start + 1 .. end - 1 */
+ start_ip += 1;
+
+ /* Calculate end IP and netmask */
+ end_ip = start_ip;
+ for (i = 31 - prefix; i >= 0; i--) {
+ end_ip |= (1 << i);
+ netmask &= ~(1 << i);
+ }
+
+ end_ip -= 1;
+
+ if (prefix_out)
+ *prefix_out = prefix;
+
+ if (start_out)
+ *start_out = start_ip;
+
+ if (end_out)
+ *end_out = end_ip;
+
+ if (mask_out)
+ *mask_out = netmask;
+
+ return true;
+}
diff --git a/src/util.h b/src/util.h
index 2679c117..e6b4747f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -107,4 +107,7 @@ static inline uint32_t util_secure_fill_with_msb(uint32_t val)
return (uint32_t) (val >> (sizeof(val)*8 - 1)) * 0xFFFFFFFF;
}
+bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix, uint32_t *start_out,
+ uint32_t *end_out, uint32_t *mask_out);
+
#endif /* __UTIL_H */
--
2.26.2
2 months, 3 weeks
[PATCH v5 1/6] util: add util_ip_prefix_tohl
by James Prestwood
Parses an IP prefix notation string into prefix, start, end, and
netmask. All values are returned in host order.
---
src/util.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/util.h | 3 ++
2 files changed, 98 insertions(+)
diff --git a/src/util.c b/src/util.c
index 13b01c81..5dc5f15d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -28,6 +28,8 @@
#include <stdio.h>
#include <sys/uio.h>
#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include <ell/ell.h>
@@ -218,3 +220,96 @@ const char *util_get_username(const char *identity)
return identity;
}
+
+static bool is_prefix_valid(uint32_t ip, unsigned int prefix)
+{
+ int i;
+
+ for (i = 31 - prefix; i >= 0; i--) {
+ if (ip & (1 << i))
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Parse a prefix notation IP string (e.g. A.B.C.D/E) into an IP range and
+ * netmask. All returned IP addresses/mask will be in host order. The start/end
+ * IP will only include the usable IP range where the last octet is not zero or
+ * 255.
+ */
+bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix_out,
+ uint32_t *start_out, uint32_t *end_out,
+ uint32_t *mask_out)
+{
+ struct in_addr ia;
+ int i;
+ unsigned int prefix;
+ char no_prefix[16];
+ char *endp;
+ uint32_t start_ip;
+ uint32_t end_ip;
+ uint32_t netmask = 0xffffffff;
+ int len = strlen(ip) - 1;
+ bool found = false;
+ uint8_t dots = 0;
+
+ /* Count dots and find prefix offset */
+ for (i = 0; i <= len; i++) {
+ if (ip[i] == '.')
+ dots++;
+ else if (ip[i] == '/') {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found || dots != 3)
+ return false;
+
+ memcpy(no_prefix, ip, i);
+ no_prefix[i] = '\0';
+
+ /* Check if IP preceeding prefix is valid */
+ if (inet_aton(no_prefix, &ia) < 0 || ia.s_addr == 0)
+ return false;
+
+ prefix = strtol(ip + i + 1, &endp, 0);
+ if (*endp != '\0')
+ return false;
+
+ if (prefix < 1 || prefix > 31)
+ return false;
+
+ start_ip = ntohl(ia.s_addr);
+
+ if (!is_prefix_valid(start_ip, prefix))
+ return false;
+
+ /* Usable range is start + 1 .. end - 1 */
+ start_ip += 1;
+
+ /* Calculate end IP and netmask */
+ end_ip = start_ip;
+ for (i = 31 - prefix; i >= 0; i--) {
+ end_ip |= (1 << i);
+ netmask &= ~(1 << i);
+ }
+
+ end_ip -= 1;
+
+ if (prefix_out)
+ *prefix_out = prefix;
+
+ if (start_out)
+ *start_out = start_ip;
+
+ if (end_out)
+ *end_out = end_ip;
+
+ if (mask_out)
+ *mask_out = netmask;
+
+ return true;
+}
diff --git a/src/util.h b/src/util.h
index 2679c117..e6b4747f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -107,4 +107,7 @@ static inline uint32_t util_secure_fill_with_msb(uint32_t val)
return (uint32_t) (val >> (sizeof(val)*8 - 1)) * 0xFFFFFFFF;
}
+bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix, uint32_t *start_out,
+ uint32_t *end_out, uint32_t *mask_out);
+
#endif /* __UTIL_H */
--
2.26.2
2 months, 4 weeks