【问题标题】:Wireless ESSID and Signal Strength in C using wireless.h使用 wireless.h 在 C 中的无线 ESSID 和信号强度
【发布时间】:2020-03-24 01:04:37
【问题描述】:

我目前有一个应用程序,它使用 popen(nmcli...) 获取 essid 和信号强度,我正在尝试使用 wireless.h 和 ioctl 切换到纯 C。获取 ESSID 很容易,但是尝试通过 SIOCGIWSTATS 获取强度/质量一直给我一个“不支持操作”错误。谁能发现我做错了什么,或者只是我的无线驱动程序实际上不支持 SIOCGIWSTATS?

请忽略全局变量的使用,这只是我调试当前问题时的临时性。

谢谢,

海顿。



    #include <string.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <ifaddrs.h>
    #include <sys/types.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <linux/wireless.h>
    #include <stdlib.h>
    #include <errno.h>

    char ifname[IFNAMSIZ];
    char essid[IW_ESSID_MAX_SIZE+1];
    struct iwreq wrq;
    struct iw_statistics *iwstats;
    int sock;


    int findWifi() {
      struct ifaddrs *ifaddr, *ifa;

      if (getifaddrs(&ifaddr) == -1) {
        perror("Error getting interface addresses");
        return -1;
      }

      for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        strncpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);

        if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
          perror("Error opening INET socket");
        }

        if (ioctl(sock, SIOCGIWNAME, &wrq) == 0) {
          printf("IF: %s\n", wrq.ifr_name);
          strcpy(ifname, wrq.ifr_name);
          freeifaddrs(ifaddr);
          return sock;
        }
      }
      freeifaddrs(ifaddr);
      return 0;
    }

    int wifiInfo() {
      wrq.u.essid.pointer = essid;
      if (ioctl(sock, SIOCGIWESSID, &wrq) == -1) {
        perror("Can't open socket to obtain essid");
        return(-1);
      }

      printf("ESSID is %s\n", wrq.u.essid.pointer);

      memset(&iwstats, 0, sizeof(iwstats));

      wrq.u.data.pointer = (caddr_t) &iwstats;
      wrq.u.data.length = sizeof(&iwstats);
      wrq.u.data.flags = 1;

      // ERROR HERE...
      if (ioctl(sock, SIOCGIWSTATS, &wrq) == -1) {
        perror("Can't open socket to obtain iwstats");
        return(-1);
      }

      return(0);
    }

    int main(int argc, char const *argv[]) {
      findWifi();
      wifiInfo();
      return 0;
    }

【问题讨论】:

    标签: c wireless ioctl


    【解决方案1】:

    谁能发现我做错了什么,或者可能只是我的无线驱动程序实际上不支持 SIOCGIWSTATS?

    您的代码看起来不错,或者至少非常接近,尽管这一行需要仔细检查:

    wrq.u.data.pointer = (caddr_t) &iwstats;
    

    这在 Ubuntu 16.04 上无法编译,因为 caddr_t 未声明。即使在添加&lt;linux/types.h&gt; and &lt;sys/types.h&gt; 之后也会发生这种情况。

    谷歌搜索似乎表明这个caddr_t 是特定于 BSD 的,建议你不要使用它:

    What is the significance of caddr_t and when is it used?


    对于您问题的第二部分,您可以使用iwconfig 等常用工具检查 Wifi 驱动程序是否真的支持SIOCGIWSTATS

    【讨论】:

    • 谢谢,caddr_t 实际上来自无线工具代码,例如:github.com/HewlettPackard/wireless-tools/blob/master/…, (struct iw_statistics*) 应该可以代替。有趣的一点是:iwconfig,作为非 priv 用户,我没有列出任何质量,但我以 root 身份执行,以 root 身份运行我的 wifiInfo 我得到“参数列表太长”错误,而不是不受支持,因此可能需要查看。
    • 那个无线工具已经过时了;考虑改用 wpa_supplicant
    • @artm:wpa_supplicant 可以像无线工具 iwlist 扫描选项一样用于扫描无线网络吗?在文档中找不到方法
    【解决方案2】:

    感谢 artm 建议 iwconfig,这使我指出它不能作为非 root 用户工作。通过细微的更改,代码现在可以作为 root 工作(尽管需要一些整理,例如:删除全局变量,检查 iwstats.qual.updated 是正确的值等)。我得看看为什么非 root 不能运行它,但这是一个单独的问题。

    
    
        #include <string.h>
        #include <stdio.h>
        #include <unistd.h>
        #include <ifaddrs.h>
        #include <sys/types.h>
        #include <sys/ioctl.h>
        #include <sys/socket.h>
        #include <linux/wireless.h>
        #include <stdlib.h>
        #include <errno.h>
    
        char ifname[IFNAMSIZ];
        char essid[IW_ESSID_MAX_SIZE+1];
        struct iwreq wrq;
        struct iw_statistics iwstats;
        int sock;
    
    
        int findWifi() {
          struct ifaddrs *ifaddr, *ifa;
    
          if (getifaddrs(&ifaddr) == -1) {
            perror("Error getting interface addresses");
            return -1;
          }
    
          for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
            strncpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);
    
            if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
              perror("Error opening INET socket");
            }
    
            if (ioctl(sock, SIOCGIWNAME, &wrq) == 0) {
              printf("IF: %s\n", wrq.ifr_name);
              strcpy(ifname, wrq.ifr_name);
              freeifaddrs(ifaddr);
              return sock;
            }
          }
          freeifaddrs(ifaddr);
          return 0;
        }
    
        int wifiInfo() {
          wrq.u.essid.pointer = essid;
          if (ioctl(sock, SIOCGIWESSID, &wrq) == -1) {
            perror("Can't open socket to obtain essid");
            return(-1);
          }
    
          printf("ESSID is %s\n", wrq.u.essid.pointer);
    
          memset(&iwstats, 0, sizeof(iwstats));
    
          wrq.u.data.pointer = &iwstats;
          wrq.u.data.length = sizeof(struct iw_statistics);
          wrq.u.data.flags = 1;
    
          if (ioctl(sock, SIOCGIWSTATS, &wrq) == -1) {
            perror("Can't open socket to obtain iwstats");
            return(-1);
          }
    
          printf("Signal level is %d\n", iwstats.qual.updated);
          return(0);
        }
    
        int main(int argc, char const *argv[]) {
          findWifi();
          wifiInfo();
          return 0;
        }
    
    

    【讨论】:

      猜你喜欢
      • 2020-06-04
      • 2013-10-17
      • 2015-12-02
      • 2011-08-21
      • 1970-01-01
      • 1970-01-01
      • 2013-10-10
      • 1970-01-01
      • 2013-02-04
      相关资源
      最近更新 更多