Benedikt Mokroß Benedikt Mokroß - 1 month ago 25
C++ Question

wpa_supplicant C API undefined behavior

I managed to get the wpa_supplicant C API to work. But it behaves completly different each time I restart my Program.

The Connection succeeds every time. But then the troubles begin:

Sometimes

SCAN
replies an empty String but returns 0 (Ok).
In another run it replies
"OK\n"
and returns 0. When I loop and wait for an return of 0 and a
"OK\n"
-reply it runs forever with an empty reply and a 0 return.

In rare cases when
SCAN
returns 0 and replies
"OK\n"
I move on and wait for
SCAN_RESULTS
to return 0. At this point it behaves completely random. Sometimes it replies the whole Scan-Results. Sometimes it replies nothing but return 0 and the Scan-results are in my Event-Pipeline.
Or like in most cases: It returns 0 but does nothing. No reply, no Events. Nothing.

For debugging I reduced my Code to this snippet and try to figure out whats wrong. Im done, tried everything and I am somewhat frustrated with the Documentation of the ctrl-interface which doesn't define any workflow or tips. Im sick of reverse engineering the wpa_cli.c to figure out their flow.

I have to attach that mostly the first PING works well. Every other PING results in empty Strings.

/* some includes */

wpa_ctrl* _wpac;

static void callback(char* rply, size_t rplylen){
std::cout << std::string(rply,rplylen) << std::endl;
}

bool ScanResults() {
if(_wpac)
{
char rply[4096]; //same as in wpa_cli.c
size_t rplylen;
int retval = wpa_ctrl_request(_wpac,"SCAN_RESULTS",12,rply,&rplylen,callback);

if(retval == 0) {
std::string rplystring = std::string(rply,rplylen);
std::string message = std::string("wpa_ctrl(SCAN_RESULTS) replied: '").append(rplystring).append("' (").append(std::to_string(retval)).append(")");
std::cout << message << std::cout;
std::cout << std::string("wpa_ctrl(SCAN_RESULTS): Available (").append(std::to_string(retval)).append(")") << std::endl;
return true;
}
else
std::cout << std::string("wpa_ctrl(SCAN_RESULTS): Unavailable (").append(std::to_string(retval)).append(")") << std::endl;


return false;
}
return false;
}

bool InitScan() {
if(_wpac)
{
char rply[4096]; //same as in wpa_cli.c
size_t rplylen;
int retval = wpa_ctrl_request(_wpac,"SCAN",4,rply,&rplylen,callback);
if(retval == 0) {
std::string rplystring = std::string(rply,rplylen);
std::string message = std::string("wpa_ctrl(SCAN) replied: '").append(rplystring).append("' (").append(std::to_string(retval)).append(")");
std::cout << message << std::endl;

if(rplystring == "OK\n") {
std::string message = std::string("wpa_ctrl(SCAN): Scan initiated (").append(std::to_string(retval)).append(")");
std::cout << message << std::endl;
return true;
}
}
std::string message = std::string("wpa_ctrl(SCAN) failed: (").append(std::to_string(retval)).append(")");
std::cout << message << std::endl;
}
return false;
}


int main(){
std::string connection_string = std::string("/var/run/wpa_supplicant/").append(_interface);
wpa_ctrl* _wpac = wpa_ctrl_open(connection_string.c_str());
if(!_wpac)
return 1;

/* Well Working Attach to as Eventlistener omitted */

while(!InitScan())
sleep(1);
while(!ScanResults())
sleep(1)
return 0;
}

Answer

Try doing something like this in the appropriate places in your code

    char rply[4096];
    size_t rplylen = sizeof(rply);
    char cmd[] = "SCAN";   //maybe a bit easier to deal with since you need a command length

    int retval = wpa_ctrl_request(_wpac, cmd, sizeof(cmd)-1, rply, &rplylen, NULL);

NULL, because I suspect you really don't need a callback routine. But put one in if you want to.