4 #include <yajl/yajl_gen.h>
5 #include <yajl/yajl_version.h>
11 #define IW_ESSID_MAX_SIZE 32
16 #include <sys/param.h>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
21 #include <net/if_media.h>
22 #include <net80211/ieee80211.h>
23 #include <net80211/ieee80211_ioctl.h>
25 #define IW_ESSID_MAX_SIZE IEEE80211_NWID_LEN
29 #include <sys/param.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
34 #include <net/if_media.h>
35 #include <netproto/802_11/ieee80211.h>
36 #include <netproto/802_11/ieee80211_ioctl.h>
38 #define IW_ESSID_MAX_SIZE IEEE80211_NWID_LEN
42 #include <sys/ioctl.h>
43 #include <sys/socket.h>
45 #include <sys/types.h>
46 #include <netinet/in.h>
47 #include <netinet/if_ether.h>
48 #include <net80211/ieee80211.h>
49 #include <net80211/ieee80211_ioctl.h>
54 #define WIRELESS_INFO_FLAG_HAS_ESSID (1 << 0)
55 #define WIRELESS_INFO_FLAG_HAS_QUALITY (1 << 1)
56 #define WIRELESS_INFO_FLAG_HAS_SIGNAL (1 << 2)
57 #define WIRELESS_INFO_FLAG_HAS_NOISE (1 << 3)
59 #define PERCENT_VALUE(value, total) ((int)(value * 100 / (float)total + 0.5f))
63 char essid[IW_ESSID_MAX_SIZE + 1];
74 static int get_wireless_info(const char *interface, wireless_info_t *info) {
75 memset(info, 0, sizeof(wireless_info_t));
78 int skfd = iw_sockets_open();
80 perror("iw_sockets_open");
85 if (iw_get_basic_config(skfd, interface, &wcfg) < 0) {
90 if (wcfg.has_essid && wcfg.essid_on) {
91 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
92 strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE);
93 info->essid[IW_ESSID_MAX_SIZE] = '\0';
96 /* Wireless quality is a relative value in a driver-specific range.
97 Signal and noise level can be either relative or absolute values
98 in dBm. Furthermore, noise and quality can be expressed directly
99 in dBm or in RCPI (802.11k), which we convert to dBm. When those
100 values are expressed directly in dBm, they range from -192 to 63,
101 and since the values are packed into 8 bits, we need to perform
102 8-bit arithmetic on them. Assume absolute values if everything
103 else fails (driver bug). */
106 if (iw_get_range_info(skfd, interface, &range) < 0) {
112 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
117 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
118 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
119 info->quality = stats.qual.qual;
120 info->quality_max = range.max_qual.qual;
121 info->quality_average = range.avg_qual.qual;
122 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
125 if (stats.qual.updated & IW_QUAL_RCPI) {
126 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
127 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
128 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
130 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
131 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
132 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
136 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
137 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
138 info->signal_level = stats.qual.level;
139 if (info->signal_level > 63)
140 info->signal_level -= 256;
141 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
143 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
144 info->noise_level = stats.qual.noise;
145 if (info->noise_level > 63)
146 info->noise_level -= 256;
147 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
151 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
152 info->signal_level = stats.qual.level;
153 info->signal_level_max = range.max_qual.level;
154 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
156 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
157 info->noise_level = stats.qual.noise;
158 info->noise_level_max = range.max_qual.noise;
159 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
165 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
166 info->quality = stats.qual.qual;
167 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
169 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
170 info->quality = stats.qual.level;
171 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
173 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
174 info->quality = stats.qual.noise;
175 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
180 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
181 info->bitrate = wrq.u.bitrate.value;
186 #if defined(__FreeBSD__) || defined(__DragonFly__)
188 uint8_t buf[24 * 1024], *cp;
189 struct ieee80211req na;
190 char network_id[IEEE80211_NWID_LEN + 1];
192 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
195 memset(&na, 0, sizeof(na));
196 strlcpy(na.i_name, interface, sizeof(na.i_name));
197 na.i_type = IEEE80211_IOC_SSID;
198 na.i_data = &info->essid[0];
199 na.i_len = IEEE80211_NWID_LEN + 1;
200 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
205 if (na.i_len <= IEEE80211_NWID_LEN)
208 len = IEEE80211_NWID_LEN + 1;
209 info->essid[len -1] = '\0';
214 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
216 memset(&na, 0, sizeof(na));
217 strlcpy(na.i_name, interface, sizeof(na.i_name));
218 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
220 na.i_len = sizeof(buf);
222 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
231 struct ieee80211req_scan_result *sr;
233 sr = (struct ieee80211req_scan_result *)cp;
234 vp = (u_int8_t *)(sr + 1);
235 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
236 if (!strcmp(network_id, &info->essid[0])) {
237 info->signal_level = sr->isr_rssi;
238 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
239 info->noise_level = sr->isr_noise;
240 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
241 info->quality = sr->isr_intval;
242 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
249 struct ieee80211_bssid bssid;
250 struct ieee80211_nwid nwid;
251 struct ieee80211_nodereq nr;
253 struct ether_addr ea;
255 int s, len, ibssid, inwid;
256 u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
258 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
261 memset(&ifr, 0, sizeof(ifr));
262 ifr.ifr_data = (caddr_t)&nwid;
263 (void)strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
264 inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
266 memset(&bssid, 0, sizeof(bssid));
267 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
268 ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
270 if (ibssid != 0 || inwid != 0) {
277 if (nwid.i_len <= IEEE80211_NWID_LEN)
278 len = nwid.i_len + 1;
280 len = IEEE80211_NWID_LEN + 1;
282 strncpy(&info->essid[0], nwid.i_nwid, len);
283 info->essid[IW_ESSID_MAX_SIZE] = '\0';
284 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
287 /* Signal strength */
289 memset(&zero_bssid, 0, sizeof(zero_bssid));
290 if (ibssid == 0 && memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
291 memcpy(&ea.ether_addr_octet, bssid.i_bssid, sizeof(ea.ether_addr_octet));
293 bzero(&nr, sizeof(nr));
294 bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
295 strlcpy(nr.nr_ifname, interface, sizeof(nr.nr_ifname));
297 if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
299 info->signal_level_max = IEEE80211_NODEREQ_RSSI(&nr);
301 info->signal_level = nr.nr_rssi;
303 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
314 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
316 char *outwalk = buffer;
317 wireless_info_t info;
321 const char *ip_address = get_ip_addr(interface);
322 if (ip_address == NULL) {
323 START_COLOR("color_bad");
324 outwalk += sprintf(outwalk, "%s", format_down);
327 START_COLOR("color_good");
330 if (get_wireless_info(interface, &info)) {
332 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
333 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
337 START_COLOR("color_bad");
340 for (; *walk != '\0'; walk++) {
342 *(outwalk++) = *walk;
346 if (BEGINS_WITH(walk+1, "quality")) {
347 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
348 if (info.quality_max)
349 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
351 outwalk += sprintf(outwalk, "%d", info.quality);
355 walk += strlen("quality");
358 if (BEGINS_WITH(walk+1, "signal")) {
359 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
360 if (info.signal_level_max)
361 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
363 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
367 walk += strlen("signal");
370 if (BEGINS_WITH(walk+1, "noise")) {
371 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
372 if (info.noise_level_max)
373 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
375 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
379 walk += strlen("noise");
382 if (BEGINS_WITH(walk+1, "essid")) {
383 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
384 outwalk += sprintf(outwalk, "%s", info.essid);
387 walk += strlen("essid");
390 if (BEGINS_WITH(walk+1, "ip")) {
391 outwalk += sprintf(outwalk, "%s", ip_address);
392 walk += strlen("ip");
396 if (BEGINS_WITH(walk+1, "bitrate")) {
399 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
401 outwalk += sprintf(outwalk, "%s", br_buffer);
402 walk += strlen("bitrate");
409 OUTPUT_FULL_TEXT(buffer);