Find the answer to your Linux question:
Results 1 to 2 of 2
Hi, I am writing a C program to get wireless statistics (the same found in /proc/net/wireless) using ioctl. It works but since the iw_statistics structure has its parameters as unsigned, ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    May 2010
    Location
    Madrid
    Posts
    32

    get wireless statistics from C


    Hi,
    I am writing a C program to get wireless statistics (the same found in /proc/net/wireless) using ioctl. It works but since the iw_statistics structure has its parameters as unsigned, when I get level and noise values they are not displayed as negative (as they are in /proc/net/wireless).
    To solve this and make that values look like they should I substract 256, but this is a temporaly patch and I guess I am missing something. How should I solve this correctly and independently of the driver I use?
    Here is the code:

    Code:
    int main(int argc, char *argv[]){
    
        int sockfd;
        struct iw_statistics stats;
        struct iwreq req;
    
        if(argc != 2){
            fprintf(stderr, "Usage: %s iface\n", argv[0]);
            return -1;
        }
    
        memset(&stats, 0, sizeof(stats));
        memset(&req, 0, sizeof(req));
        sprintf(req.ifr_name, "wlan0"); // for debug, hardcode the iface
        req.u.data.pointer = &stats;
        req.u.data.length = sizeof(stats);
    #ifdef CLEAR_UPDATED
        req.u.data.flags = 1;
    #endif
    
    
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
    
        if(ioctl(sockfd, SIOCGIWSTATS, &req) == -1) {
            perror("ioctl SIOCGIWSTATS failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
    
        close(sockfd);
    
    // I have to substract 256 to get the values as they are shown in /proc/net/wireless, why iw_statistics parameters are unsigned? what I am doing wrong?
    
        printf("qual: %d level: %d noise: %d updated: %d\n",
            stats.qual.qual, stats.qual.level - 256, stats.qual.noise - 256, stats.qual.updated);
    
    return 0;
    }

    Another much simpler way is to read it form proc and, to avoid the need and overhead of parsing all the information, count the position of the level info, but I think this is not very portable since it depends on the format of /proc/net/wireless... Is this way of doing it advisable?

    Code:
    int main(void){
    
        int i;
        char buf[32];
        FILE *fproc;
    
        fproc = fopen("/proc/net/wireless", "r");
    
        if(fproc == NULL){
            perror("failed to open /proc/net/wireless");
            return -1; 
        }   
            
        for(i=0; i<31; i++){  // Level is in position 31
            fscanf(fproc, "%s", buf);
    //      printf("i: %d : %s\n",i, buf);
        }   
    
        printf("Level: %d\n", atoi(buf));
        fclose(fproc);
    
        return 0;
    
    }
    Last edited by occam25; 03-31-2013 at 12:39 PM.

  2. #2
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,517
    Have you tried just casting the values to a signed integer? In any case, don't try the -256 thing - your results may not be valid. BTW, the -256 bit will only work if these are byte (char) values. If that is the case, then do this (or something like it):
    Code:
    int main(int argc, char *argv[])
    {
    
        int sockfd;
        struct iw_statistics stats;
        struct iwreq req;
    
        if(argc != 2)
        {
            fprintf(stderr, "Usage: %s iface\n", argv[0]);
            return -1;
        }
    
        memset(&stats, 0, sizeof(stats));
        memset(&req, 0, sizeof(req));
        sprintf(req.ifr_name, "wlan0"); // for debug, hardcode the iface
        req.u.data.pointer = &stats;
        req.u.data.length = sizeof(stats);
    #ifdef CLEAR_UPDATED
        req.u.data.flags = 1;
    #endif
    
    
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
        {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
    
        if(ioctl(sockfd, SIOCGIWSTATS, &req) == -1)
        {
            perror("ioctl SIOCGIWSTATS failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }
    
        close(sockfd);
    
    // I have to substract 256 to get the values as they are shown in /proc/net/wireless, why iw_statistics parameters are unsigned? what I am doing wrong?
    
        printf("qual: %d level: %d noise: %d updated: %d\n",
            (int)((char)stats.qual.qual), (int)((char)stats.qual.level), (int)((char)stats.qual.noise), (int)((char)stats.qual.updated));
    
    return 0;
    }
    You do this, because in the linux/wireless.h header file, these variables are defined NOT as integers, but as unsigned 8-bit byte values (an unsigned char in other words). So, we are first casting away the unsigned data with the (char) cast, and then making it compatible with your formatting string with the (int) cast.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •