LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Wireless Networking (http://www.linuxquestions.org/questions/linux-wireless-networking-41/)
-   -   ioctl call for obtaining the RSSI (http://www.linuxquestions.org/questions/linux-wireless-networking-41/ioctl-call-for-obtaining-the-rssi-611337/)

saioha 01-05-2008 11:47 AM

ioctl call for obtaining the RSSI
 
Hello, my name is Saioa and I am new in the forum, but I have a problem and I wonder if you could help me.

I have installed an Ad-Hoc network with several PCs, for proving over them the routing protocol called OLSR. For doing this I have used the WiFi card of Netgear WG311v3.
The problem is that I need to obtain the received signal power, RSSI, in my computer from the driver every time a new message of the other nodes arrives.
I work over Linux. I have tried to read this value from the file /proc/net/wireless, but this way is not valid as the information of this file is updated more slowly than I receive the messages. I know that the signal power can also be obtained by using ioctl calls, but I don’t know exactly which ioctl I must use. I would also like to know in which unit would this ioctl give me the value, and if there is any way of getting it in dBm. But this matter is secondary, the most important for me is to know which ioctl I have to use to obtain the signal power.

Thank you very much, bye.

osor 01-05-2008 10:30 PM

Quote:

Originally Posted by saioha (Post 3012388)
I have tried to read this value from the file /proc/net/wireless, but this way is not valid as the information of this file is updated more slowly than I receive the messages.

The file is not “updated” any more slowly than it is read. As you may know, the proc filesystem is a virtual filesystem. Every time a process reads from one of the virtual files which reside on that filesystem, an interface to the kernel is called. There is no caching (at least not by the kernel). Your shell or C library might cache the reads, so you might try rewinding the stream associated with the open file descriptor.

Anyway, the update interval is driver-specific, and if you told us what driver you are using, it might even be patchable. Using ioctls and reading from /proc/net/wireless are equivalent except for specification of units and clearing the update indicator flags, which is also driver dependent (more on this later).
Quote:

Originally Posted by saioha (Post 3012388)
I know that the signal power can also be obtained by using ioctl calls, but I don’t know exactly which ioctl I must use. I would also like to know in which unit would this ioctl give me the value, and if there is any way of getting it in dBm. But this matter is secondary, the most important for me is to know which ioctl I have to use to obtain the signal power.

Well, the ioctl to use goes by the macro SIOCGIWSTATS (mnemonically, Socket IOCtl Get Inet Wireless STATisticS). It is a socket ioctl which means that instead of a descriptor to a normal file, the first argument is a socket file descriptor (any socket will do since we don’t modify any socket attributes). The WE API specifies that the third argument of any ioctl of the form SIOC?IW* will be a pointer to a struct iwreq, and in this case, the interface name is given. Here is a small sample program which will attempt to perform the ioctl, and upon success, it will print the signal level, tell you whether or not it is in dBm, and tell you whether the value was updated.
Code:

#include <linux/wireless.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <stdio.h>
#include <stdlib.h>

/* The name of the interface */
#ifndef IW_NAME
#define IW_NAME "eth1"
#endif

int main()
{
        int sockfd;
        struct iw_statistics stats;
        struct iwreq req = {
                .ifr_name = IW_NAME,
                .u.data = {
                        .pointer = &stats,
#ifdef CLEAR_UPDATED
                        .flags = 1
#endif
                }
        };

        /* Any old socket will do, and a datagram socket is pretty cheap */
        if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
                perror("Could not create simple datagram socket");
                exit(EXIT_FAILURE);
        }

        /* Perform the ioctl */
        if(ioctl(sockfd, SIOCGIWSTATS, &req) == -1) {
                perror("Error performing SIOCGIWSTATS on " IW_NAME);
                close(sockfd);
                exit(EXIT_FAILURE);
        }

        close(sockfd);

        printf("Signal level%s is %d%s.\n",
              (stats.qual.updated & IW_QUAL_DBM ? " (in dBm)" :""),
              stats.qual.level,
              (stats.qual.updated & IW_QUAL_LEVEL_UPDATED ? " (updated)" :""));

        return 0;
}

The code is self-explanatory except for a few parts. The field stats.qual.updated holds a bunch of flags. One of the bits (specifically IW_QUAL_DBM) tells if the quality values (both level and noise) are reported with units of dBm. Most modern drivers will set this bit and you will know the levels exactly in dBm. Some modern drivers will intentionally not set this bit to indicate a different form of measurement (usually a percentage value). Some older drivers do not know about that flag, so the units could be anything.

The other bit we are concerned with is IW_QUAL_LEVEL_UPDATED, which is supposed to tell us if the value has been updated. This is the same as the presence of a dot after a number in the output of /proc/net/wireless. We can modify whether we want all the flags of the form IW_QUAL_*_UPDATED to be cleared by setting the req.u.data.flags field to nonzero. The flags are not only cleared in the copy of the statistics record given to your process, but also in the driver’s record itself. The meaning of this clearing of these bits is driver-specific. I have left this feature in as conditionally compilable (if you pass the option -DCLEAR_UPDATED to your compiler). The behavior when reading from the procfile is to clear the flags. A side effect when you clear the flags with the ioctl which is not present when using the procfile is that you lose any information about whether the flag was previously set.

Jessard 07-31-2008 07:48 PM

Quote:

Originally Posted by osor (Post 3012901)
Here is a small sample program which will attempt to perform the ioctl, and upon success, it will print the signal level, tell you whether or not it is in dBm, and tell you whether the value was updated.

Hello osor,

I'm trying to learn some things along the same lines as saioha, so I compiled and ran your example program, but for me the ioctl call fails with:

"Error performing SIOCGIWSTATS on ath0: Argument list too long"

(Of course, I'm assuming I was correct to change eth1 to ath0, in my case... using wifi0 yields "Operation not supported.")

Any tips? :)

(P.S: I'm using an Atheros AR5BMB5 transmitter module / AR5005GS chipset with the MadWifi 0.9.4 driver)

wes314 06-24-2009 03:36 AM

Quote:

Originally Posted by Jessard (Post 3232615)
Hello osor,

I'm trying to learn some things along the same lines as saioha, so I compiled and ran your example program, but for me the ioctl call fails with:

"Error performing SIOCGIWSTATS on ath0: Argument list too long"

(Of course, I'm assuming I was correct to change eth1 to ath0, in my case... using wifi0 yields "Operation not supported.")

Any tips? :)

(P.S: I'm using an Atheros AR5BMB5 transmitter module / AR5005GS chipset with the MadWifi 0.9.4 driver)


>>>>>>>


To fix that error i tracked it down to having an invalid length.
You can fix it by adding this:

req.u.data.length = sizeof(iw_statistics);



The following code works for me:

int main()
{
int sockfd;
struct iw_statistics stats;
struct iwreq req;
memset(&stats, 0, sizeof(stats));
memset(&req, 0, sizeof(iwreq));
sprintf(req.ifr_name, "rausb0");
req.u.data.pointer = &stats;
req.u.data.length = sizeof(iw_statistics);
#ifdef CLEAR_UPDATED
req.u.data.flags = 1;
#endif

/* Any old socket will do, and a datagram socket is pretty cheap */
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Could not create simple datagram socket");
exit(EXIT_FAILURE);
}

/* Perform the ioctl */
if(ioctl(sockfd, SIOCGIWSTATS, &req) == -1) {
perror("Error performing SIOCGIWSTATS");
close(sockfd);
exit(EXIT_FAILURE);
}

close(sockfd);

printf("Signal level%s is %d%s.\n",
(stats.qual.updated & IW_QUAL_DBM ? " (in dBm)" :""),
stats.qual.level,
(stats.qual.updated & IW_QUAL_LEVEL_UPDATED ? " (updated)" :""));

return 0;
}

Output with my hand moving around the antenna:

Signal level is 203.
# ./wifi_signal
Signal level is 203.
# ./wifi_signal
Signal level is 203.
# ./wifi_signal
Signal level is 203.
# ./wifi_signal
Signal level is 213.
# ./wifi_signal
Signal level is 217.
# ./wifi_signal
Signal level is 215.
# ./wifi_signal
Signal level is 217.
# ./wifi_signal
Signal level is 217.

bogd4n.iv4n 07-09-2009 11:21 AM

Code doesn't compile
 
I compiled your code wes314 and I got the following errors:

In file included from /usr/include/linux/wireless.h:74,
from test.c:1:
/usr/include/linux/if.h:168: error: field ‘ifru_addr’ has incomplete type
/usr/include/linux/if.h:169: error: field ‘ifru_dstaddr’ has incomplete type
/usr/include/linux/if.h:170: error: field ‘ifru_broadaddr’ has incomplete type
/usr/include/linux/if.h:171: error: field ‘ifru_netmask’ has incomplete type
/usr/include/linux/if.h:172: error: field ‘ifru_hwaddr’ has incomplete type
In file included from test.c:1:
/usr/include/linux/wireless.h:739: error: field ‘addr’ has incomplete type
/usr/include/linux/wireless.h:765: error: field ‘bssid’ has incomplete type
/usr/include/linux/wireless.h:823: error: field ‘addr’ has incomplete type
/usr/include/linux/wireless.h:836: error: field ‘addr’ has incomplete type
/usr/include/linux/wireless.h:849: error: field ‘bssid’ has incomplete type
/usr/include/linux/wireless.h:857: error: field ‘src_addr’ has incomplete type
/usr/include/linux/wireless.h:868: error: field ‘bssid’ has incomplete type
/usr/include/linux/wireless.h:922: error: field ‘ap_addr’ has incomplete type
/usr/include/linux/wireless.h:923: error: field ‘addr’ has incomplete type
test.c: In function ‘main’:
test.c:18: warning: incompatible implicit declaration of built-in function ‘memset’
test.c:19: error: ‘iwreq’ undeclared (first use in this function)
test.c:19: error: (Each undeclared identifier is reported only once
test.c:19: error: for each function it appears in.)
test.c:22: error: ‘iw_statistics’ undeclared (first use in this function)

Please help.

peiweijun 10-19-2009 08:45 AM

Quote:

Originally Posted by bogd4n.iv4n (Post 3602312)
I compiled your code wes314 and I got the following errors:

In file included from /usr/include/linux/wireless.h:74,
from test.c:1:
/usr/include/linux/if.h:168: error: field ‘ifru_addr’ has incomplete type
/usr/include/linux/if.h:169: error: field ‘ifru_dstaddr’ has incomplete type
/usr/include/linux/if.h:170: error: field ‘ifru_broadaddr’ has incomplete type
/usr/include/linux/if.h:171: error: field ‘ifru_netmask’ has incomplete type
/usr/include/linux/if.h:172: error: field ‘ifru_hwaddr’ has incomplete type
In file included from test.c:1:
/usr/include/linux/wireless.h:739: error: field ‘addr’ has incomplete type
/usr/include/linux/wireless.h:765: error: field ‘bssid’ has incomplete type
/usr/include/linux/wireless.h:823: error: field ‘addr’ has incomplete type
/usr/include/linux/wireless.h:836: error: field ‘addr’ has incomplete type
/usr/include/linux/wireless.h:849: error: field ‘bssid’ has incomplete type
/usr/include/linux/wireless.h:857: error: field ‘src_addr’ has incomplete type
/usr/include/linux/wireless.h:868: error: field ‘bssid’ has incomplete type
/usr/include/linux/wireless.h:922: error: field ‘ap_addr’ has incomplete type
/usr/include/linux/wireless.h:923: error: field ‘addr’ has incomplete type
test.c: In function ‘main’:
test.c:18: warning: incompatible implicit declaration of built-in function ‘memset’
test.c:19: error: ‘iwreq’ undeclared (first use in this function)
test.c:19: error: (Each undeclared identifier is reported only once
test.c:19: error: for each function it appears in.)
test.c:22: error: ‘iw_statistics’ undeclared (first use in this function)

Please help.

move
"#include <sys/types.h>
#include <sys/socket.h>"
to the front of
"#include <wireless.h>"

aztroboy 06-17-2010 11:35 AM

the meaning of those signal values?
 
Quote:

Originally Posted by wes314 (Post 3584272)
>>>>>>>


To fix that error i tracked it down to having an invalid length.
You can fix it by adding this:

req.u.data.length = sizeof(iw_statistics);



The following code works for me:

int main()
{
int sockfd;
struct iw_statistics stats;
struct iwreq req;
memset(&stats, 0, sizeof(stats));
memset(&req, 0, sizeof(iwreq));
sprintf(req.ifr_name, "rausb0");
req.u.data.pointer = &stats;
req.u.data.length = sizeof(iw_statistics);
#ifdef CLEAR_UPDATED
req.u.data.flags = 1;
#endif

/* Any old socket will do, and a datagram socket is pretty cheap */
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Could not create simple datagram socket");
exit(EXIT_FAILURE);
}

/* Perform the ioctl */
if(ioctl(sockfd, SIOCGIWSTATS, &req) == -1) {
perror("Error performing SIOCGIWSTATS");
close(sockfd);
exit(EXIT_FAILURE);
}

close(sockfd);

printf("Signal level%s is %d%s.\n",
(stats.qual.updated & IW_QUAL_DBM ? " (in dBm)" :""),
stats.qual.level,
(stats.qual.updated & IW_QUAL_LEVEL_UPDATED ? " (updated)" :""));

return 0;
}

Output with my hand moving around the antenna:

Signal level is 203.
# ./wifi_signal
Signal level is 203.
# ./wifi_signal
Signal level is 203.
# ./wifi_signal
Signal level is 203.
# ./wifi_signal
Signal level is 213.
# ./wifi_signal
Signal level is 217.
# ./wifi_signal
Signal level is 215.
# ./wifi_signal
Signal level is 217.
# ./wifi_signal
Signal level is 217.

Hi! I've run your code in an OpenWRT node successfully

Now, I understand that those values shown on the output are signal strenght but from where or what exactly?

Let me explain my case: I want to get the RSSI values from a client by running a script on an OpenWRT node. I would like to know how to get the RSSI from a specific client.

As far as I know, it's possible by doing: "wl rssi <mac>" but that's not a really good approach, it's not very reliable.

So, how do I get the RSSI value from a specific client?

Thanks.

usmanca 09-08-2011 12:47 PM

aztroboy any updates
 
Hi Aztroboy,
Did you get any success in reading rssi from the client more accurately and reliably ?

usman

Bladerunner1989 09-09-2011 10:13 AM

Hi,
actually I was also struggling with this problem for a while. Specifically speaking in my case I have an ad-hoc network and I want to have a pair RSSI value - MAC-address of the node from whom it was received. But when I run ioctl call in ad-hoc mode it says: "Error performing SIOCGIWSTATS: operation not supported". However, when I run sniffer to see if there are beacons transmitted in the ad-hoc network I see them regularly. So I don't see the reason why it shouldn't work (it works when using infrastructure mode, but this is not what I want). Obviously, using libpcap will provide much more flexible solution, but I want to make sure that there is no solution with ioctl before taking more work.
And by the way, I am using Atheros 5k.
Thanks in advance!

usmanca 09-09-2011 11:12 AM

infrastructure mode
 
Hi, Could you share your code for infrastructure mode. Are you able to get the RSSI and MAC address pair of the the client nodes ? I am interested in this. Please guide me.

Regards,

Bladerunner1989 09-11-2011 03:23 PM

@usmanca
My code is essentially the same as published by osor. I am not able to get a MAC address corresponding to RSSI value. I didn't find any code of IOCTL command for that. I am switching to libpcap as there are no answers. However in some other forum a person reported that ioctl call worked to report RSSI value for ad-hoc but only on some wireless cards. So I guess it is a question of luck.
Regards.

xsguo 03-27-2012 12:47 PM

I am very interested in this question
 
Quote:

Originally Posted by usmanca (Post 4467392)
Hi, Could you share your code for infrastructure mode. Are you able to get the RSSI and MAC address pair of the the client nodes ? I am interested in this. Please guide me.

Regards,

Could you share your code for me, also i want to obtain the RSSI and MAC address pair of the client nodes. Very thanks


All times are GMT -5. The time now is 09:00 PM.