Linux - Wireless NetworkingThis forum is for the discussion of wireless networking in Linux.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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.
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
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.
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)
Last edited by Jessard; 07-31-2008 at 06:58 PM.
Reason: Adding hardware/driver information...
/* 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);
}
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.
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)
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>"
/* 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);
}
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?
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!
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.
@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.
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
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.