6

Before people jump to conclusion saying this is a duplicate post, I'd like to point out that I have gone through the other posts on this topic but really haven't found a solution.


What I need

My goal is to access the wpa_supplicant from a C program to do the following:

  1. See active connections
  2. Detect when interfaces goes down
  3. Connect to AP/Setup an AP and so on

What I've found out

  • I don't need DBus if I need to write a C program to communicate with wpa_supplicant
  • I can make use of the functions in wpa_ctrl.h by just including these files in my project directory
  • Here are some links I found related to this question. 1, 2, 3
  • I've also gone through the official documentation which talks about external programs using wpa_ctrl.c

Why the above does not actually solve the problem

  • Most of the posts I found on SO and other related websites regarding this issue point to resources like official documentation which is good but does not solve the problem
  • In a lot of these posts, people have given up pursuing this or have worked out a solution but haven't posted it online.
  • For a novice in this topic, it'll be helpful if one can post a working example -- the 'hello world' of wpa_supplicant.

What I've done so far

  • From this link, I copied wpa_supplicant-2.5/src/common/wpa_ctrl.h into wpa_supplicant-2.5/src/utils directory (since common.h had many dependencies). I then wrote a simple C program hostapd_cli.c in the same directory which is shown below. I get an undefined reference to 'wpa_ctrl_open' error

    #include "includes.h"
    #include <dirent.h>
    #include "wpa_ctrl.h"
    #include "common.h"
    static struct wpa_ctrl *ctrl_conn;
    static int hostapd_cli_quit = 0;
    static int hostapd_cli_attached = 0;
    static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
    static char *ctrl_ifname = NULL;
    static int ping_interval = 5;
    
    int main()
    {
        ctrl_conn = wpa_ctrl_open(ctrl_iface_dir);
        if (!ctrl_conn){
            printf("Could not get ctrl interface!\n");
            return -1;
        }
        return 0;
    }
    

Makefile

C=gcc
CFLAGS=-lpthread
DEPS = includes.h wpa_ctrl.h common.h
OBJ = wpa_ctrl.o hostapd_cli.o

%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

main: $(OBJ)
gcc -o $@ $^ $(CFLAGS)

.PHONY: clean

clean:
rm -f *.o *~ core $(INCDIR)/*~ 

Build log

 gcc -o main wpa_ctrl.o hostapd_cli.o -lpthread
 hostapd_cli.o: In function `main':
 hostapd_cli.c:(.text+0xf): undefined reference to `wpa_ctrl_open'
 collect2: error: ld returned 1 exit status
 Makefile:10: recipe for target 'main' failed
 make: *** [main] Error 1

There's not much material on how to use these files and integrate it to an external project or how to compile it and I'm kinda clueless. Any help on how to proceed will be really appreciated.

Edit 1: Corrected typo and added build log

Community
  • 1
  • 1
am3
  • 681
  • 2
  • 12
  • 30
  • From the official doc you have linked, referring to `wpa_ctrl.c`: "External programs can link this file into them". That is, you need to make a copy of that file, compile it and link that into your program. – kaylum Jul 06 '16 at 03:59
  • Does that mean, in my makefile I add wpa_ctrl.c? In my makefile, OBJ = wpa_ctrl.c testProg.c – am3 Jul 06 '16 at 04:06
  • Yes. Except it should be listing the `.o` files not the `.c` files. – kaylum Jul 06 '16 at 04:09
  • Yes. Sorry, that was a typo. Including the right `.o` files still generates the same error. – am3 Jul 06 '16 at 04:11
  • Perhaps you still have something wrong with your Makeifile. If you want help then you need to show the updated Makefile and the build log. – kaylum Jul 06 '16 at 04:15
  • Ok, edited makefile and added log. – am3 Jul 06 '16 at 04:19
  • If the other questions didn't help you, it may be more persuasive if you enumerate the ones that are similar and explain why your question is different. Not only does that demonstrate that you've done your research, but it can reduce the likelihood of answers simply repeating advice that you didn't find helpful. – Toby Speight Jul 06 '16 at 08:20
  • Okay, I've added a section on why the existing resources havent been super useful. – am3 Jul 06 '16 at 15:42

3 Answers3

6

This answer comes too late for OP to find useful, but perhaps it will help others who stumble on this same problem.

In wpa_supplicant-2.9, you don't need to compile wpa_ctrl.c with your own source files. Instead, first build libwpa_client.so (or libwpa_client.a) from the wpa_supplicant sources: $make -C wpa_supplicant libwpa_client.so

Then, link the shared libraries to building your own program. You will need to add the include paths too. Eg) $gcc main.c -Iwpa_supplicant-2.9/src/common -I.wpa_supplicant2-9/src/utils -lwpa_client

Lenny
  • 388
  • 3
  • 15
3

undefined reference to `wpa_ctrl_open'

That's a linker error. If the command,

$ nm wpa_ctrl.o

reveals that it defines wpa_ctrl_open, then your immediate problem may be just the command-line order. Try:

gcc -o main hostapd_cli.o wpa_ctrl.o -lpthread

because hostapd_cli references symbols in wpa_ctrl.o. Otherwise, you need to find the source code that does define that symbol, so you can link to it.

Edit: Apparently you need to define a couple of symbols.

HTH.

Community
  • 1
  • 1
James K. Lowden
  • 7,574
  • 1
  • 16
  • 31
  • I don't think its a linker issue. I think I don't have the right files. `wpa_ctrl.c` does not define `wpa_ctrl_open()` method. This is the part where it gets confusing because the official documentation says any external document can just link `wpa_ctrl.c` and use `wpa_ctrl_open()` – am3 Jul 06 '16 at 18:44
  • It's defined. See my edit, and line 86 of https://w1.fi/cgit/hostap/tree/src/common/wpa_ctrl.c. – James K. Lowden Jul 06 '16 at 19:41
  • I think this is not clear enough and not free-standing. `wpa_ctrl.c` defines TWO wpa_ctrl_open functions, but the definitions are gated by macros. The link under "define a couple of symbols" in the answer shows that for typical Linux use you need to define the `CONFIG_CTRL_IFACE` and `CONFIG_CTRL_IFACE_UNIX` macros when compiling `wpa_ctrl.c` to get the function that is useful on Linux. The same file works on Windows with different macros. IMHO the answer could show this information and have reference links to show where the info comes from. – cardiff space man Sep 01 '17 at 18:54
  • I could cross compile the library (for arm, raspberry) and get it to work by defining these two macros. For a regular compiling (running on X86-64) it wasnt necessary to define them. – Vincent Achard Oct 23 '21 at 07:28
3

Okay, so I got it to work on my raspberry pi. All credit goes to Gyph on the raspberry pi forums (link: https://www.raspberrypi.org/forums/viewtopic.php?t=42949).

Files needed

in wpa_supplicant/src/common : 
wpa_ctrl.h 
wpa_ctrl.c


in wpa_supplicant/src/utils : 
build_config.h 
common.h 
includes.h 
os.h 
os_unix.c 
wpabuf.h 
wpa_debug.h
your own file

Run following commands to compile:

gcc -Wall -Wextra -I ./ -MMD -c -g -o wpa_ctrl.o wpa_ctrl.c -D CONFIG_CTRL_IFACE -D CONFIG_CTRL_IFACE_UNIX
gcc -Wall -Wextra -I ./ -MMD -c -g -o os_unix.o os_unix.c -D CONFIG_CTRL_IFACE -D CONFIG_CTRL_IFACE_UNIX
gcc -Wall -Wextra -o your_file your_file.c os_unix.o wpa_ctrol.o

To work with wpa_supplicant, I've found it easiest to just copy hostapd_cli, and adjust it to my needs. Note that if you are with wpa_supplicant and not hostapd, you will have to adjust the ctrl_iface_dir variable. (For me it is " /var/run/wpa_supplicant").

Tigris
  • 133
  • 8