wpa-cli: Support monitor mode without action file.

Message ID 1497464962-26237-1-git-send-email-greearb@candelatech.com
State Rejected
Headers show

Commit Message

Ben Greear June 14, 2017, 6:29 p.m.
From: Ben Greear <greearb@candelatech.com>

I wanted a way to start wpa_cli, have it do the keep-alive ping,
and print events as they are received.  I do not want an action file,
and I do not need interactive mode, and I want to run
this in a way where stdin may not be open.

So, introduce '-m' monitor mode.

wpa_cli -m -g /var/run/wpa_supplicant_if_wiphy0

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 wpa_supplicant/wpa_cli.c | 37 ++++++++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 13 deletions(-)

Comments

Jouni Malinen April 17, 2018, 10:04 p.m. | #1
On Wed, Jun 14, 2017 at 11:29:22AM -0700, greearb@candelatech.com wrote:
> I wanted a way to start wpa_cli, have it do the keep-alive ping,
> and print events as they are received.  I do not want an action file,
> and I do not need interactive mode, and I want to run
> this in a way where stdin may not be open.
> 
> So, introduce '-m' monitor mode.
> 
> wpa_cli -m -g /var/run/wpa_supplicant_if_wiphy0

This and the related (I'd assume) "wpa_cli: Don't buffer stdout." patch
were left in my queue for more consideration and I did not really ever
find time to go through the details before now.. It looks like this is
used to enable wpa_cli to be used by some other program to receive
wpa_supplicant messages. That sounds quite complex compared to simply
using wpa_ctrl.c or wpaspy.py (or similar implementation of socket
communication in other programming languages). I'm not really convinced
that wpa_cli should have such mode and instead, I'd recommend
implementing direct wpa_supplicant socket access in whatever the program
is that would be using this no-buffering-stdout from wpa_cli.
Ben Greear April 17, 2018, 10:18 p.m. | #2
On 04/17/2018 03:04 PM, Jouni Malinen wrote:
> On Wed, Jun 14, 2017 at 11:29:22AM -0700, greearb@candelatech.com wrote:
>> I wanted a way to start wpa_cli, have it do the keep-alive ping,
>> and print events as they are received.  I do not want an action file,
>> and I do not need interactive mode, and I want to run
>> this in a way where stdin may not be open.
>>
>> So, introduce '-m' monitor mode.
>>
>> wpa_cli -m -g /var/run/wpa_supplicant_if_wiphy0
>
> This and the related (I'd assume) "wpa_cli: Don't buffer stdout." patch
> were left in my queue for more consideration and I did not really ever
> find time to go through the details before now.. It looks like this is
> used to enable wpa_cli to be used by some other program to receive
> wpa_supplicant messages. That sounds quite complex compared to simply
> using wpa_ctrl.c or wpaspy.py (or similar implementation of socket
> communication in other programming languages). I'm not really convinced
> that wpa_cli should have such mode and instead, I'd recommend
> implementing direct wpa_supplicant socket access in whatever the program
> is that would be using this no-buffering-stdout from wpa_cli.

I do want to receive events, such as notification of when 4-way auth
completed so I could know when to start the dhcp client process ('iw event'
doesn't seem to offer an event for this, so that is why I was using
supplicant).

I don't want to poll, as that would be inefficient in my setup where I have
lots of virtual stations, so it seemed that wpa_cli in a monitor mode
would be a good option, and it seemed less work to tweak wpa_cli than
to re-write something similar.

Maybe I am missing your point, but how would I use wpa_ctrl.c or wpaspy.py in this
case?

Thanks,
Ben
Jouni Malinen April 17, 2018, 10:27 p.m. | #3
On Tue, Apr 17, 2018 at 03:18:02PM -0700, Ben Greear wrote:
> I do want to receive events, such as notification of when 4-way auth
> completed so I could know when to start the dhcp client process ('iw event'
> doesn't seem to offer an event for this, so that is why I was using
> supplicant).

So this would be the exact use case that wpa_cli -a<action script> was
added for..

> I don't want to poll, as that would be inefficient in my setup where I have
> lots of virtual stations, so it seemed that wpa_cli in a monitor mode
> would be a good option, and it seemed less work to tweak wpa_cli than
> to re-write something similar.
> 
> Maybe I am missing your point, but how would I use wpa_ctrl.c or wpaspy.py in this
> case?

Either use the action script for events like the CONNECTED event (which
will cover that DHCP client start) or wait for monitor socket events in
your own application (that would apparently now wait on stdout lines
from wpa_cli) if you need some messages for debugging purposes where it
does not make sense to support them with an action script. The latter
case could use wpa_ctrl.c or wpaspy.py as an helper:

ctrl = wpa_ctrl_open(..)
wpa_ctrl_attach(ctrl)

and then either blocking:

while (wpa_ctrl_recv(Ctrl, buf, &buflen) == 0) {
    process..
}

or nonblocking:

fd = wpa_ctrl_get_fd(ctrl)
select/poll/etc. on fd being readable and run wpa_ctrl_recv()
Ben Greear April 17, 2018, 10:39 p.m. | #4
On 04/17/2018 03:27 PM, Jouni Malinen wrote:
> On Tue, Apr 17, 2018 at 03:18:02PM -0700, Ben Greear wrote:
>> I do want to receive events, such as notification of when 4-way auth
>> completed so I could know when to start the dhcp client process ('iw event'
>> doesn't seem to offer an event for this, so that is why I was using
>> supplicant).
>
> So this would be the exact use case that wpa_cli -a<action script> was
> added for..

Well, my 'action' needs to be handled by my big complicated program, so I didn't
think having it call a script was the proper thing to do.

And, just FYI, sometimes at least my hacked wpa_cli stops receiving messages from
the supplicant after a while...restarting wpa_cli fixes things, and debugging
made me think it might be a supplicant issue.  I can detect it easily enough
and restarting wpa_cli was easier than figuring out the real problem so
far...

>
>> I don't want to poll, as that would be inefficient in my setup where I have
>> lots of virtual stations, so it seemed that wpa_cli in a monitor mode
>> would be a good option, and it seemed less work to tweak wpa_cli than
>> to re-write something similar.
>>
>> Maybe I am missing your point, but how would I use wpa_ctrl.c or wpaspy.py in this
>> case?
>
> Either use the action script for events like the CONNECTED event (which
> will cover that DHCP client start) or wait for monitor socket events in
> your own application (that would apparently now wait on stdout lines
> from wpa_cli) if you need some messages for debugging purposes where it
> does not make sense to support them with an action script. The latter
> case could use wpa_ctrl.c or wpaspy.py as an helper:
>
> ctrl = wpa_ctrl_open(..)
> wpa_ctrl_attach(ctrl)
>
> and then either blocking:
>
> while (wpa_ctrl_recv(Ctrl, buf, &buflen) == 0) {
>     process..
> }
>
> or nonblocking:
>
> fd = wpa_ctrl_get_fd(ctrl)
> select/poll/etc. on fd being readable and run wpa_ctrl_recv()

Ok, that would probably work for me, but at this point, I have already
hacked wpa_cli to work, so might be a while before I get to re-writing
this.

Thanks,
Ben

Patch

diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 510f385..7edacac 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -54,6 +54,7 @@  static const char *pid_file = NULL;
 static const char *action_file = NULL;
 static int ping_interval = 5;
 static int interactive = 0;
+static int do_monitor = 0;
 static char *ifname_prefix = NULL;
 
 static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
@@ -89,6 +90,7 @@  static void usage(void)
 	       "events from\n"
 	       "       wpa_supplicant\n"
 	       "  -B = run a daemon in the background\n"
+	       "  -m = Run in monitor mode, even if we don't have an action file.\n"
 	       "  default path: " CONFIG_CTRL_IFACE_DIR "\n"
 	       "  default interface: first interface found in socket path\n");
 	print_help(NULL);
@@ -123,7 +125,7 @@  static int wpa_cli_open_connection(const char *ifname, int attach)
 	if (ctrl_conn == NULL)
 		return -1;
 
-	if (attach && interactive)
+	if (attach && (interactive || do_monitor))
 		mon_conn = wpa_ctrl_open(ifname);
 	else
 		mon_conn = NULL;
@@ -168,7 +170,7 @@  static int wpa_cli_open_connection(const char *ifname, int attach)
 		return -1;
 	}
 
-	if (attach && interactive)
+	if (attach && (interactive || do_monitor))
 		mon_conn = wpa_ctrl_open2(cfile, client_socket_dir);
 	else
 		mon_conn = NULL;
@@ -178,7 +180,7 @@  static int wpa_cli_open_connection(const char *ifname, int attach)
 	if (mon_conn) {
 		if (wpa_ctrl_attach(mon_conn) == 0) {
 			wpa_cli_attached = 1;
-			if (interactive)
+			if (interactive || do_monitor)
 				eloop_register_read_sock(
 					wpa_ctrl_get_fd(mon_conn),
 					wpa_cli_mon_receive, NULL, NULL);
@@ -200,7 +202,7 @@  static void wpa_cli_close_connection(void)
 		return;
 
 	if (wpa_cli_attached) {
-		wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
+		wpa_ctrl_detach((interactive || do_monitor) ? mon_conn : ctrl_conn);
 		wpa_cli_attached = 0;
 	}
 	wpa_ctrl_close(ctrl_conn);
@@ -3682,6 +3684,9 @@  static void wpa_cli_action_process(const char *msg)
 	if (eloop_terminated())
 		return;
 
+	if (!action_file)
+		return;
+
 	pos = msg;
 	if (os_strncmp(pos, "IFNAME=", 7) == 0) {
 		const char *end;
@@ -3818,8 +3823,9 @@  static void wpa_cli_reconnect(void)
 			return;
 		}
 
-		if (interactive) {
-			update_ifnames(ctrl_conn);
+		if (interactive || do_monitor) {
+			if (interactive)
+				update_ifnames(ctrl_conn);
 			mon_conn = wpa_ctrl_open(global);
 			if (mon_conn) {
 				if (wpa_ctrl_attach(mon_conn) == 0) {
@@ -4269,6 +4275,7 @@  static void wpa_cli_action(struct wpa_ctrl *ctrl)
 	int fd;
 
 	fd = wpa_ctrl_get_fd(ctrl);
+
 	eloop_register_timeout(ping_interval, 0, wpa_cli_action_ping,
 			       ctrl, NULL);
 	eloop_register_read_sock(fd, wpa_cli_action_receive, ctrl, NULL);
@@ -4369,7 +4376,7 @@  int main(int argc, char *argv[])
 		return -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "a:Bg:G:hi:p:P:s:v");
+		c = getopt(argc, argv, "a:Bg:G:hi:mp:P:s:v");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -4391,6 +4398,9 @@  int main(int argc, char *argv[])
 		case 'v':
 			printf("%s\n", wpa_cli_version);
 			return 0;
+		case 'm':
+			do_monitor = 1;
+			break;
 		case 'i':
 			os_free(ctrl_ifname);
 			ctrl_ifname = os_strdup(optarg);
@@ -4415,7 +4425,7 @@  int main(int argc, char *argv[])
 	 */
 	setbuf(stdout, NULL);
 
-	interactive = (argc == optind) && (action_file == NULL);
+	interactive = (argc == optind) && (action_file == NULL) && !do_monitor;
 
 	if (interactive)
 		printf("%s\n\n%s\n\n", wpa_cli_version, cli_license);
@@ -4436,8 +4446,9 @@  int main(int argc, char *argv[])
 			return -1;
 		}
 
-		if (interactive) {
-			update_ifnames(ctrl_conn);
+		if (interactive || do_monitor) {
+			if (interactive)
+				update_ifnames(ctrl_conn);
 			mon_conn = wpa_ctrl_open(global);
 			if (mon_conn) {
 				if (wpa_ctrl_attach(mon_conn) == 0) {
@@ -4458,7 +4469,7 @@  int main(int argc, char *argv[])
 
 	eloop_register_signal_terminate(wpa_cli_terminate, NULL);
 
-	if (ctrl_ifname == NULL)
+	if (ctrl_ifname == NULL && !do_monitor)
 		ctrl_ifname = wpa_cli_get_default_ifname();
 
 	if (interactive) {
@@ -4473,7 +4484,7 @@  int main(int argc, char *argv[])
 			return -1;
 		}
 
-		if (action_file) {
+		if (action_file || do_monitor) {
 			if (wpa_ctrl_attach(ctrl_conn) == 0) {
 				wpa_cli_attached = 1;
 			} else {
@@ -4486,7 +4497,7 @@  int main(int argc, char *argv[])
 		if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
 			return -1;
 
-		if (action_file)
+		if (action_file || do_monitor)
 			wpa_cli_action(ctrl_conn);
 		else
 			ret = wpa_request(ctrl_conn, argc - optind,