9 #define IW_ESSID_MAX_SIZE 32
14 #include <sys/param.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
19 #include <net/if_media.h>
20 #include <net80211/ieee80211.h>
21 #include <net80211/ieee80211_ioctl.h>
23 #define IW_ESSID_MAX_SIZE IEEE80211_NWID_LEN
28 #define WIRELESS_INFO_FLAG_HAS_ESSID (1 << 0)
29 #define WIRELESS_INFO_FLAG_HAS_QUALITY (1 << 1)
30 #define WIRELESS_INFO_FLAG_HAS_SIGNAL (1 << 2)
31 #define WIRELESS_INFO_FLAG_HAS_NOISE (1 << 3)
33 #define PERCENT_VALUE(value, total) ((int)(value * 100 / (float)total + 0.5f))
37 char essid[IW_ESSID_MAX_SIZE + 1];
48 static int get_wireless_info(const char *interface, wireless_info_t *info) {
49 memset(info, 0, sizeof(wireless_info_t));
52 int skfd = iw_sockets_open();
54 perror("iw_sockets_open");
59 if (iw_get_basic_config(skfd, interface, &wcfg) < 0) {
64 if (wcfg.has_essid && wcfg.essid_on) {
65 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
66 strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE);
67 info->essid[IW_ESSID_MAX_SIZE] = '\0';
70 /* Wireless quality is a relative value in a driver-specific range.
71 Signal and noise level can be either relative or absolute values
72 in dBm. Furthermore, noise and quality can be expressed directly
73 in dBm or in RCPI (802.11k), which we convert to dBm. When those
74 values are expressed directly in dBm, they range from -192 to 63,
75 and since the values are packed into 8 bits, we need to perform
76 8-bit arithmetic on them. Assume absolute values if everything
77 else fails (driver bug). */
80 if (iw_get_range_info(skfd, interface, &range) < 0) {
86 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
91 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
92 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
93 info->quality = stats.qual.qual;
94 info->quality_max = range.max_qual.qual;
95 info->quality_average = range.avg_qual.qual;
96 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
99 if (stats.qual.updated & IW_QUAL_RCPI) {
100 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
101 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
102 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
104 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
105 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
106 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
110 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
111 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
112 info->signal_level = stats.qual.level;
113 if (info->signal_level > 63)
114 info->signal_level -= 256;
115 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
117 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
118 info->noise_level = stats.qual.noise;
119 if (info->noise_level > 63)
120 info->noise_level -= 256;
121 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
125 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
126 info->signal_level = stats.qual.level;
127 info->signal_level_max = range.max_qual.level;
128 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
130 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
131 info->noise_level = stats.qual.noise;
132 info->noise_level_max = range.max_qual.noise;
133 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
139 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
140 info->quality = stats.qual.qual;
141 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
143 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
144 info->quality = stats.qual.level;
145 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
147 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
148 info->quality = stats.qual.noise;
149 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
154 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
155 info->bitrate = wrq.u.bitrate.value;
162 uint8_t buf[24 * 1024], *cp;
163 struct ieee80211req na;
164 char network_id[IEEE80211_NWID_LEN + 1];
166 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
169 memset(&na, 0, sizeof(na));
170 strlcpy(na.i_name, interface, sizeof(na.i_name));
171 na.i_type = IEEE80211_IOC_SSID;
172 na.i_data = &info->essid[0];
173 na.i_len = IEEE80211_NWID_LEN + 1;
174 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
179 if (na.i_len <= IEEE80211_NWID_LEN)
182 len = IEEE80211_NWID_LEN + 1;
183 info->essid[len -1] = '\0';
188 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
190 memset(&na, 0, sizeof(na));
191 strlcpy(na.i_name, interface, sizeof(na.i_name));
192 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
194 na.i_len = sizeof(buf);
196 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
205 struct ieee80211req_scan_result *sr;
207 sr = (struct ieee80211req_scan_result *)cp;
208 vp = (u_int8_t *)(sr + 1);
209 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
210 if (!strcmp(network_id, &info->essid[0])) {
211 info->signal_level = sr->isr_rssi;
212 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
213 info->noise_level = sr->isr_noise;
214 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
215 info->quality = sr->isr_intval;
216 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
224 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
226 char *outwalk = buffer;
227 wireless_info_t info;
231 if (get_wireless_info(interface, &info)) {
233 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
234 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
238 START_COLOR("color_bad");
241 for (; *walk != '\0'; walk++) {
243 *(outwalk++) = *walk;
247 if (BEGINS_WITH(walk+1, "quality")) {
248 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
249 if (info.quality_max)
250 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
252 outwalk += sprintf(outwalk, "%d", info.quality);
256 walk += strlen("quality");
259 if (BEGINS_WITH(walk+1, "signal")) {
260 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
261 if (info.signal_level_max)
262 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
264 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
268 walk += strlen("signal");
271 if (BEGINS_WITH(walk+1, "noise")) {
272 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
273 if (info.noise_level_max)
274 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
276 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
280 walk += strlen("noise");
283 if (BEGINS_WITH(walk+1, "essid")) {
284 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
285 outwalk += sprintf(outwalk, "%s", info.essid);
288 walk += strlen("essid");
291 if (BEGINS_WITH(walk+1, "ip")) {
292 const char *ip_address = get_ip_addr(interface);
293 outwalk += sprintf(outwalk, "%s", (ip_address ? ip_address : "no IP"));
294 walk += strlen("ip");
298 if (BEGINS_WITH(walk+1, "bitrate")) {
301 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
303 outwalk += sprintf(outwalk, "%s", br_buffer);
304 walk += strlen("bitrate");
310 OUTPUT_FULL_TEXT(buffer);