[PATCH v2] NAN: Use a portable os_ffs() instead of ffs()
Chaitanya Tata
chaitanya.mgit at gmail.com
Thu Sep 10 13:46:03 PDT 2026
ffs() is declared in <strings.h> only when __MISC_VISIBLE,
__XSI_VISIBLE >= 700 or __POSIX_VISIBLE < 200809 (glibc and picolibc
both use this scheme). Building with _POSIX_C_SOURCE=200809L and
without _DEFAULT_SOURCE/_XOPEN_SOURCE, a legitimate and fairly common
strict-POSIX build configuration, therefore hides the declaration and
fails with an implicit-function-declaration error.
Add a portable os_ffs() to os.h: __builtin_ffs() on GCC/clang,
_BitScanForward() on MSVC (matching the _MSC_VER handling already
used throughout this header), and a manual bit-scan fallback
otherwise. Use it in place of ffs() in the NAN code.
v2: Use a portable os_ffs() (os.h) instead of __builtin_ffs(),
which is a GCC/clang-only extension and would not have compiled with
the MSVC toolchain that CONFIG_NATIVE_WINDOWS already supports
elsewhere in this codebase.
Signed-off-by: Chaitanya Tata <Chaitanya.Tata at nordicsemi.no>
---
src/nan/nan.c | 4 ++--
src/nan/nan_util.c | 6 ++---
src/utils/os.h | 39 +++++++++++++++++++++++++++++++++
wpa_supplicant/nan_supplicant.c | 2 +-
4 files changed, 45 insertions(+), 6 deletions(-)
diff --git a/src/nan/nan.c b/src/nan/nan.c
index 0a5439ad1..9f0dbbead 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -2933,7 +2933,7 @@ nan_peer_get_committed_avail_add(const struct nan_data *nan,
return;
}
- idx = ffs(le_to_host16(bc_chan->chan_bitmap)) - 1;
+ idx = os_ffs(le_to_host16(bc_chan->chan_bitmap)) - 1;
if (idx < 0) {
wpa_printf(MSG_DEBUG,
"NAN: No channel found in chan_bitmap 0x%04x for oper_class %u",
@@ -2961,7 +2961,7 @@ nan_peer_get_committed_avail_add(const struct nan_data *nan,
op->op_class);
return;
} else {
- idx = ffs(bc_chan->pri_chan_bitmap) - 1;
+ idx = os_ffs(bc_chan->pri_chan_bitmap) - 1;
if (idx < 0) {
wpa_printf(MSG_DEBUG,
"NAN: No primary channel found in pri_chan_bitmap 0x%04x",
diff --git a/src/nan/nan_util.c b/src/nan/nan_util.c
index 78dcde0a3..ab276530b 100644
--- a/src/nan/nan_util.c
+++ b/src/nan/nan_util.c
@@ -934,7 +934,7 @@ int nan_add_avail_attrs(struct nan_data *nan, u8 sequence_id,
while (map_ids_bitmap) {
struct nan_channels pot_chans;
- u8 map_id = ffs(map_ids_bitmap) - 1;
+ u8 map_id = os_ffs(map_ids_bitmap) - 1;
u16 ctrl = map_id << NAN_AVAIL_CTRL_MAP_ID_POS |
NAN_AVAIL_CTRL_POTENTIAL_CHANGED;
@@ -1462,7 +1462,7 @@ static int nan_get_control_channel(struct nan_data *nan, u8 op_class,
if (!op || op_class > 130)
return -1;
- idx = ffs(cbm) - 1;
+ idx = os_ffs(cbm) - 1;
if (idx < 0) {
wpa_printf(MSG_DEBUG,
"NAN: No channel found in chan_bitmap 0x%04x for oper_class %u",
@@ -1498,7 +1498,7 @@ static int nan_get_control_channel(struct nan_data *nan, u8 op_class,
return -1;
}
- idx = ffs(pri_cbm) - 1;
+ idx = os_ffs(pri_cbm) - 1;
if (op->bw == BW80 || op->bw == BW80P80)
return freq - 30 + idx * 20;
diff --git a/src/utils/os.h b/src/utils/os.h
index 9d6c34096..f956d5872 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -582,6 +582,45 @@ static inline int os_snprintf_error(size_t size, int res)
}
+/**
+ * os_ffs - Find the position of the first (least significant) set bit
+ * @val: Value to check
+ * Returns: Position of the first set bit (counting from 1), or 0 if val
+ * does not have any bits set
+ *
+ * This is a portable replacement for the ffs() function which, unlike
+ * ffs(), is always available regardless of the C library/compiler in use
+ * and the requested feature test macros (glibc/picolibc based libraries
+ * hide ffs() unless _DEFAULT_SOURCE, _XOPEN_SOURCE >= 700, or similar is
+ * defined in addition to any strict _POSIX_C_SOURCE request).
+ */
+#ifdef _MSC_VER
+#include <intrin.h>
+static inline int os_ffs(unsigned int val)
+{
+ unsigned long index;
+
+ if (!val)
+ return 0;
+ _BitScanForward(&index, val);
+ return (int) index + 1;
+}
+#elif defined(__GNUC__) || defined(__clang__)
+#define os_ffs(val) __builtin_ffs(val)
+#else
+static inline int os_ffs(unsigned int val)
+{
+ int i;
+
+ if (!val)
+ return 0;
+ for (i = 1; !(val & 1); i++, val >>= 1)
+ ;
+ return i;
+}
+#endif
+
+
static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
{
if (size && nmemb > (~(size_t) 0) / size)
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 18057c366..c2fcb42a2 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -2514,7 +2514,7 @@ wpas_nan_fill_ndp_schedule_chan(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_TESTING_OPTIONS */
tbm->duration = wpa_s->nan_capa.slot_duration >> 5;
- tbm->period = ffs(wpa_s->nan_capa.schedule_period) - 7;
+ tbm->period = os_ffs(wpa_s->nan_capa.schedule_period) - 7;
tbm->offset = 0;
tbm->len = bitmap_len;
os_memcpy(tbm->bitmap, bitmap_data, bitmap_len);
--
2.43.0
More information about the Hostap
mailing list