[RFC] wpa_supplicant: Added Support for Varlink folder structure

Kartik Rajput kartik.mgit at gmail.com
Fri Jul 3 15:57:36 PDT 2026


Added Basic Scalfholding for Varlink Server and socket.

Configured Makefile for linking libvarlink C bindings to wpa_supplicant in the Makefiles. Also appeneded clean instructions for the object/output files.

Added a new flag -V representing varlink enablement, without it off by default.

In defconfig added a simple flag CONFIG_CTRL_IFACE_VARLINK to enable/disable compilation.

Varlink is still disabled via wpa_params, even if compiled with, until -V is supplied through the initial call.

Used dbus Makefile as base for Varlink.

varlink_common_i.h is for internal uses. varlink_common.h, varlink_server.c, and varlink_events.c is for init and public event calls, used by the notify.c

varlink_methods.c and varlink_methods.h is for client side usage.

org.wlan.supplicant.varlink is for varlink structure and maybe (MAYBE) parsing.

Signed-off-by: Kartik Rajput <kartik.mgit at gmail.com>
---
 wpa_supplicant/Makefile                       |  16 +++
 wpa_supplicant/defconfig                      |   3 +
 wpa_supplicant/main.c                         |  11 +-
 wpa_supplicant/notify.c                       |  16 +++
 wpa_supplicant/varlink/.gitignore             |   1 +
 wpa_supplicant/varlink/Makefile               |  57 ++++++++++
 .../varlink/org.wlan.supplicant.varlink       |   4 +
 wpa_supplicant/varlink/varlink_common.h       |  40 +++++++
 wpa_supplicant/varlink/varlink_common_i.h     |  20 ++++
 wpa_supplicant/varlink/varlink_events.c       |   7 ++
 wpa_supplicant/varlink/varlink_methods.c      |  53 +++++++++
 wpa_supplicant/varlink/varlink_methods.h      |  20 ++++
 wpa_supplicant/varlink/varlink_server.c       | 104 ++++++++++++++++++
 wpa_supplicant/wpa_supplicant.c               |   5 +
 wpa_supplicant/wpa_supplicant_i.h             |  14 +++
 15 files changed, 370 insertions(+), 1 deletion(-)
 create mode 100644 wpa_supplicant/varlink/.gitignore
 create mode 100644 wpa_supplicant/varlink/Makefile
 create mode 100644 wpa_supplicant/varlink/org.wlan.supplicant.varlink
 create mode 100644 wpa_supplicant/varlink/varlink_common.h
 create mode 100644 wpa_supplicant/varlink/varlink_common_i.h
 create mode 100644 wpa_supplicant/varlink/varlink_events.c
 create mode 100644 wpa_supplicant/varlink/varlink_methods.c
 create mode 100644 wpa_supplicant/varlink/varlink_methods.h
 create mode 100644 wpa_supplicant/varlink/varlink_server.c

diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 2b82c42c8..58885bcd5 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1800,6 +1800,21 @@ CFLAGS += $(DBUS_INCLUDE)
 LIBS += $(DBUS_LIBS)
 endif
 
+ifdef CONFIG_CTRL_IFACE_VARLINK
+CFLAGS += -DCONFIG_CTRL_IFACE_VARLINK
+OBJS += varlink/varlink_server.o
+OBJS += varlink/varlink_methods.o
+OBJS += varlink/varlink_events.o
+ifndef VARLINK_LIBS
+VARLINK_LIBS := $(shell $(PKG_CONFIG) --libs libvarlink)
+endif
+ifndef VARLINK_INCLUDE
+VARLINK_INCLUDE := $(shell $(PKG_CONFIG) --cflags libvarlink)
+endif
+CFLAGS += $(VARLINK_INCLUDE)
+LIBS += $(VARLINK_LIBS)
+endif
+
 ifdef CONFIG_READLINE
 OBJS_c += ../src/utils/edit_readline.o
 LIBS_c += -lreadline -lncurses
@@ -2399,6 +2414,7 @@ libpasn.so: $(LIBPASNSO)
 clean: common-clean
 	$(MAKE) -C ../src clean
 	$(MAKE) -C dbus clean
+	$(MAKE) -C varlink clean
 	rm -f core *~ *.o *.d *.gcno *.gcda *.gcov
 	rm -f eap_*.so $(WINALL) eapol_test preauth_test
 	rm -f wpa_priv
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index bc865ce5f..a9cb4c460 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -380,6 +380,9 @@ CONFIG_CTRL_IFACE_DBUS_NEW=y
 # Add introspection support for new DBus control interface
 CONFIG_CTRL_IFACE_DBUS_INTRO=y
 
+# Add support for varlink control interface
+CONFIG_CTRL_IFACE_VARLINK=y
+
 # Add support for loading EAP methods dynamically as shared libraries.
 # When this option is enabled, each EAP method can be either included
 # statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index eeb3606ad..4a787cb0a 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -213,7 +213,7 @@ int main(int argc, char *argv[])
 
 	for (;;) {
 		c = getopt(argc, argv,
-			   "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvWyz:");
+			   "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuVvWyz:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -313,6 +313,15 @@ int main(int argc, char *argv[])
 			params.dbus_ctrl_interface = 1;
 			break;
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+		case 'V':
+			params.varlink_ctrl_interface = 1;
+			break;
+#else
+		case 'V':
+			printf("Varlink is not compiled with wpa_supplicant in this version!\n");
+			break;
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
 		case 'v':
 			printf("%s\n", wpa_supplicant_version);
 			exitcode = 0;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index af1b4e3da..d56bb173f 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -17,6 +17,9 @@
 #include "binder/binder.h"
 #include "dbus/dbus_common.h"
 #include "dbus/dbus_new.h"
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+#include "varlink/varlink_common.h"
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
 #include "rsn_supp/wpa.h"
 #include "rsn_supp/pmksa_cache.h"
 #include "fst/fst.h"
@@ -38,6 +41,14 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global)
 	}
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+	if (global->params.varlink_ctrl_interface) {
+		global->varlink = wpas_varlink_init(global);
+		if (global->varlink == NULL)
+			return -1;
+	}
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
+
 #ifdef CONFIG_BINDER
 	global->binder = wpas_binder_init(global);
 	if (!global->binder)
@@ -55,6 +66,11 @@ void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
 		wpas_dbus_deinit(global->dbus);
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+	if (global->varlink)
+		wpas_varlink_deinit(global->varlink);
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
+
 #ifdef CONFIG_BINDER
 	if (global->binder)
 		wpas_binder_deinit(global->binder);
diff --git a/wpa_supplicant/varlink/.gitignore b/wpa_supplicant/varlink/.gitignore
new file mode 100644
index 000000000..c792507d2
--- /dev/null
+++ b/wpa_supplicant/varlink/.gitignore
@@ -0,0 +1 @@
+libwpavarlink.a
\ No newline at end of file
diff --git a/wpa_supplicant/varlink/Makefile b/wpa_supplicant/varlink/Makefile
new file mode 100644
index 000000000..e49c04506
--- /dev/null
+++ b/wpa_supplicant/varlink/Makefile
@@ -0,0 +1,57 @@
+all: libwpavarlink.a
+
+clean:
+	rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+	rm -f libwpavarlink.a
+
+install:
+	@echo Nothing to be made.
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+PKG_CONFIG ?= pkg-config
+CFLAGS += -I../../src -I../../src/utils
+
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
+	@$(E) "  CC " $<
+
+
+ifdef CONFIG_WPS
+CFLAGS += -DCONFIG_WPS
+endif
+
+CFLAGS += -DCONFIG_CTRL_IFACE_VARLINK
+
+ifndef VARLINK_LIBS
+VARLINK_LIBS := $(shell $(PKG_CONFIG) --libs libvarlink)
+endif
+ifndef VARLINK_INCLUDE
+VARLINK_INCLUDE := $(shell $(PKG_CONFIG) --cflags libvarlink)
+endif
+
+CFLAGS += $(VARLINK_INCLUDE)
+
+LIB_OBJS= \
+	varlink_server.o \
+	varlink_methods.o \
+	varlink_events.o 
+
+libwpavarlink.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/varlink/org.wlan.supplicant.varlink b/wpa_supplicant/varlink/org.wlan.supplicant.varlink
new file mode 100644
index 000000000..05194f3dd
--- /dev/null
+++ b/wpa_supplicant/varlink/org.wlan.supplicant.varlink
@@ -0,0 +1,4 @@
+interface org.wlan.supplicant
+
+# Returns the current state of the daemon
+method GetState() -> (state: string)
diff --git a/wpa_supplicant/varlink/varlink_common.h b/wpa_supplicant/varlink/varlink_common.h
new file mode 100644
index 000000000..f13d8f3de
--- /dev/null
+++ b/wpa_supplicant/varlink/varlink_common.h
@@ -0,0 +1,40 @@
+/*
+ * wpa_supplicant Varlink control interface - common definitions
+ * Copyright (c) 2026, Kartik Rajput <incorrectmail101 at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+*/
+
+#ifndef HOSTAP_VARLINK_COMMON_H
+#define HOSTAP_VARLINK_COMMON_H
+
+#define WPAS_VARLINK_ADDRESS       "unix:/run/wpa_supplicant/varlink"
+#define WPAS_VARLINK_FILE_PATH		"/run/wpa_supplicant/varlink"
+#define WPAS_VARLINK_PARENT_FOLDER       "/run/wpa_supplicant"
+
+#define WPAS_VARLINK_INTERFACE     "fi.w1.wpasupplicant"
+
+#define WPAS_VARLINK_VENDOR        "fi.w1"
+#define WPAS_VARLINK_PRODUCT       "wpa_supplicant"
+#define WPAS_VARLINK_VERSION       "1"
+#define WPAS_VARLINK_VENDOR_URL    "https://w1.fi/"
+
+struct wpas_varlink_priv;
+struct wpa_global;
+
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+	struct wpas_varlink_priv * wpas_varlink_init(struct wpa_global * global);
+	void wpas_varlink_deinit(struct wpas_varlink_priv * priv);
+#else
+	static inline struct wpas_varlink_priv * wpas_varlink_init(struct wpa_global *global)
+	{
+		return NULL;
+	}
+
+	static inline void wpas_varlink_deinit(struct wpas_varlink_priv *priv)
+	{
+	}
+#endif
+
+#endif /* HOSTAP_VARLINK_COMMON_H */
diff --git a/wpa_supplicant/varlink/varlink_common_i.h b/wpa_supplicant/varlink/varlink_common_i.h
new file mode 100644
index 000000000..007219783
--- /dev/null
+++ b/wpa_supplicant/varlink/varlink_common_i.h
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant Varlink control interface - internal definitions
+ * Copyright (c) 2026, Kartik Rajput <incorrectmail101 at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+*/
+
+#ifndef HOSTAP_VARLINK_COMMON_I_H
+#define HOSTAP_VARLINK_COMMON_I_H
+
+#include <varlink.h>
+
+struct wpas_varlink_priv {
+	struct wpa_global * global;
+	VarlinkService * service;
+	int varlink_fd;
+};
+
+#endif /* HOSTAP_VARLINK_COMMON_I_H */ 
diff --git a/wpa_supplicant/varlink/varlink_events.c b/wpa_supplicant/varlink/varlink_events.c
new file mode 100644
index 000000000..855c04d28
--- /dev/null
+++ b/wpa_supplicant/varlink/varlink_events.c
@@ -0,0 +1,7 @@
+/*
+ * wpa_supplicant D-Bus control interface - common definitions
+ * Copyright (c) 2026, Kartik Rajput <incorrectmail101 at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+*/
\ No newline at end of file
diff --git a/wpa_supplicant/varlink/varlink_methods.c b/wpa_supplicant/varlink/varlink_methods.c
new file mode 100644
index 000000000..b6cbd77f9
--- /dev/null
+++ b/wpa_supplicant/varlink/varlink_methods.c
@@ -0,0 +1,53 @@
+/*
+ * wpa_supplicant D-Bus control interface - common definitions
+ * Copyright (c) 2026, Kartik Rajput <incorrectmail101 at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+*/
+
+#include "utils/includes.h"
+#include <varlink.h>
+
+#include "utils/common.h"
+#include "utils/wpa_debug.h"
+#include "utils/eloop.h"
+#include "varlink_common_i.h"
+#include "varlink_common.h"
+#include "../wpa_supplicant_i.h"
+
+long wpas_varlink_get_state(VarlinkService *service,
+								   VarlinkCall *call,
+								   VarlinkObject *parameters,
+								   uint64_t flags,
+								   void *userdata)
+{
+	struct wpas_varlink_priv *priv = userdata;
+	const char *ifname;
+	struct wpa_supplicant *wpa_s;
+	VarlinkObject *out = NULL;
+
+	if (varlink_object_get_string(parameters, "ifname", &ifname) < 0) {
+		return varlink_call_reply_invalid_parameter(call, "ifname");
+	}
+
+	wpa_s = wpa_supplicant_get_iface(priv->global, ifname);
+	if (wpa_s == NULL) {
+		/* If it doesn't exist, return our custom Varlink error */
+		VarlinkObject *err_params;
+		varlink_object_new(&err_params);
+		varlink_object_set_string(err_params, "ifname", ifname);
+		long ret = varlink_call_reply_error(call, WPAS_VARLINK_INTERFACE ".InterfaceUnknown", err_params);
+		varlink_object_unref(err_params);
+		return ret;
+	}
+
+	varlink_object_new(&out);
+	
+	varlink_object_set_string(out, "state", wpa_supplicant_state_txt(wpa_s->wpa_state));
+	
+	varlink_call_reply(call, out, 0);
+	varlink_object_unref(out);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/wpa_supplicant/varlink/varlink_methods.h b/wpa_supplicant/varlink/varlink_methods.h
new file mode 100644
index 000000000..f5b80e4eb
--- /dev/null
+++ b/wpa_supplicant/varlink/varlink_methods.h
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant Varlink control interface - common definitions
+ * Copyright (c) 2026, Kartik Rajput <incorrectmail101 at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+*/
+
+#ifndef HOSTAP_VARLINK_METHODS_H
+#define HOSTAP_VARLINK_METHODS_H
+
+#include <varlink.h>
+
+long wpas_varlink_get_state(VarlinkService *service,
+                            VarlinkCall *call,
+                            VarlinkObject *parameters,
+                            uint64_t flags,
+                            void *userdata);
+
+#endif /* HOSTAP_VARLINK_METHODS_H */
\ No newline at end of file
diff --git a/wpa_supplicant/varlink/varlink_server.c b/wpa_supplicant/varlink/varlink_server.c
new file mode 100644
index 000000000..a31e632ab
--- /dev/null
+++ b/wpa_supplicant/varlink/varlink_server.c
@@ -0,0 +1,104 @@
+/*
+ * wpa_supplicant D-Bus control interface - common definitions
+ * Copyright (c) 2026, Kartik Rajput <incorrectmail101 at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+*/
+
+#include "utils/includes.h"
+#include <varlink.h>
+
+#include "utils/common.h"
+#include "utils/wpa_debug.h"
+#include "utils/eloop.h"
+#include "varlink_common_i.h"
+#include "varlink_common.h"
+#include "varlink_methods.h"
+#include "../wpa_supplicant_i.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+void wpas_varlink_receive_handler(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpas_varlink_priv *priv = eloop_ctx;
+	
+	varlink_service_process_events(priv->service);
+}
+
+void wpas_varlink_deinit(struct wpas_varlink_priv * priv){
+	if (priv == NULL)
+		return;
+		
+	if (priv->varlink_fd >= 0) {
+		eloop_unregister_read_sock(priv->varlink_fd);
+	}
+	
+	if (priv->service) {
+		varlink_service_free(priv->service);
+	}
+
+	wpa_printf(MSG_DEBUG, "varlink: Unlink previous socket '%s'", WPAS_VARLINK_FILE_PATH);
+	unlink("/run/wpa_supplicant/varlink");
+	
+	wpa_printf(MSG_DEBUG, "varlink: De-Register varlink object '%s'", WPAS_VARLINK_ADDRESS);
+
+	os_free(priv);
+}
+
+struct wpas_varlink_priv * wpas_varlink_init(struct wpa_global * global){
+	struct wpas_varlink_priv * priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->global = global;
+	priv->varlink_fd = -1;
+
+    /* rwxr-xr-x */
+	wpa_printf(MSG_DEBUG, "varlink: Creating varlink folder '%s'", WPAS_VARLINK_PARENT_FOLDER);
+    mkdir(WPAS_VARLINK_PARENT_FOLDER, 0755);
+	/* Clear previous socket if still there */
+	wpa_printf(MSG_DEBUG, "varlink: Unlink previous socket '%s'", WPAS_VARLINK_FILE_PATH);
+    unlink(WPAS_VARLINK_FILE_PATH);
+
+	if(varlink_service_new(&priv->service, 
+						WPAS_VARLINK_VENDOR, 
+						WPAS_VARLINK_PRODUCT, 
+						WPAS_VARLINK_VERSION,
+						WPAS_VARLINK_VENDOR_URL, 
+						WPAS_VARLINK_ADDRESS, 
+						-1) != 0){
+		wpas_varlink_deinit(priv);
+		return NULL;
+	}
+
+	const char *schema = 
+		"interface " WPAS_VARLINK_INTERFACE "\n"
+		"method GetState(ifname: string) -> (state: string)\n"
+		"error InterfaceUnknown(ifname: string)\n";
+
+	if (varlink_service_add_interface(priv->service, schema,
+									"GetState", 
+									wpas_varlink_get_state, 
+									priv,
+									NULL) != 0) {
+		wpa_printf(MSG_ERROR, "varlink: Failed to add interface");
+		wpas_varlink_deinit(priv);
+		return NULL;
+	}
+
+	priv->varlink_fd = varlink_service_get_fd(priv->service);
+	if(priv->varlink_fd < 0){
+		wpas_varlink_deinit(priv);
+		return NULL;
+	}
+
+	eloop_register_read_sock(priv->varlink_fd, wpas_varlink_receive_handler, priv, NULL);
+
+	wpa_printf(MSG_DEBUG, "varlink: Register varlink object '%s'", WPAS_VARLINK_ADDRESS);
+
+	return priv;
+}
+
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 45f6ea852..9391a8813 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -8639,6 +8639,11 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 	global->params.daemonize = params->daemonize;
 	global->params.wait_for_monitor = params->wait_for_monitor;
 	global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
+
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+	global->params.varlink_ctrl_interface = params->varlink_ctrl_interface;
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
+
 	global->params.show_details = params->show_details;
 
 	if (params->pid_file) {
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 0d59c31ae..039fc1d79 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -53,6 +53,10 @@ struct ctrl_iface_global_priv;
 struct wpas_dbus_priv;
 struct wpas_binder_priv;
 
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+struct wpas_varlink_priv;
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
+
 /**
  * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
  */
@@ -206,6 +210,13 @@ struct wpa_params {
 	 */
 	int dbus_ctrl_interface;
 
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+	/**
+	 * varlink_ctrl_interface - Enable the Varlink control interface
+	*/
+	int varlink_ctrl_interface;
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
+
 	/**
 	 * wpa_debug_file_path - Path of debug file or %NULL to use stdout
 	 */
@@ -304,6 +315,9 @@ struct wpa_global {
 	struct wpa_params params;
 	struct ctrl_iface_global_priv *ctrl_iface;
 	struct wpas_dbus_priv *dbus;
+#ifdef CONFIG_CTRL_IFACE_VARLINK
+    struct wpas_varlink_priv *varlink;
+#endif /* CONFIG_CTRL_IFACE_VARLINK */
 	struct wpas_binder_priv *binder;
 	void **drv_priv;
 	size_t drv_count;
-- 
2.47.3




More information about the Hostap mailing list