c++wpa-supplicant

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;
}

Solution

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

        char rply[4096];
        size_t rplylen = sizeof(rply);
        static 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.