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/ioctl.h>
30 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <netinet/in.h>
34 #include <netinet/if_ether.h>
35 #include <net80211/ieee80211.h>
36 #include <net80211/ieee80211_ioctl.h>
41 #define WIRELESS_INFO_FLAG_HAS_ESSID (1 << 0)
42 #define WIRELESS_INFO_FLAG_HAS_QUALITY (1 << 1)
43 #define WIRELESS_INFO_FLAG_HAS_SIGNAL (1 << 2)
44 #define WIRELESS_INFO_FLAG_HAS_NOISE (1 << 3)
46 #define PERCENT_VALUE(value, total) ((int)(value * 100 / (float)total + 0.5f))
50 char essid[IW_ESSID_MAX_SIZE + 1];
61 static int get_wireless_info(const char *interface, wireless_info_t *info) {
62 memset(info, 0, sizeof(wireless_info_t));
65 int skfd = iw_sockets_open();
67 perror("iw_sockets_open");
72 if (iw_get_basic_config(skfd, interface, &wcfg) < 0) {
77 if (wcfg.has_essid && wcfg.essid_on) {
78 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
79 strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE);
80 info->essid[IW_ESSID_MAX_SIZE] = '\0';
83 /* Wireless quality is a relative value in a driver-specific range.
84 Signal and noise level can be either relative or absolute values
85 in dBm. Furthermore, noise and quality can be expressed directly
86 in dBm or in RCPI (802.11k), which we convert to dBm. When those
87 values are expressed directly in dBm, they range from -192 to 63,
88 and since the values are packed into 8 bits, we need to perform
89 8-bit arithmetic on them. Assume absolute values if everything
90 else fails (driver bug). */
93 if (iw_get_range_info(skfd, interface, &range) < 0) {
99 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
104 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
105 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
106 info->quality = stats.qual.qual;
107 info->quality_max = range.max_qual.qual;
108 info->quality_average = range.avg_qual.qual;
109 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
112 if (stats.qual.updated & IW_QUAL_RCPI) {
113 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
114 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
115 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
117 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
118 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
119 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
123 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
124 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
125 info->signal_level = stats.qual.level;
126 if (info->signal_level > 63)
127 info->signal_level -= 256;
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 if (info->noise_level > 63)
133 info->noise_level -= 256;
134 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
138 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
139 info->signal_level = stats.qual.level;
140 info->signal_level_max = range.max_qual.level;
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 info->noise_level_max = range.max_qual.noise;
146 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
152 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
153 info->quality = stats.qual.qual;
154 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
156 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
157 info->quality = stats.qual.level;
158 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
160 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
161 info->quality = stats.qual.noise;
162 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
167 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
168 info->bitrate = wrq.u.bitrate.value;
175 uint8_t buf[24 * 1024], *cp;
176 struct ieee80211req na;
177 char network_id[IEEE80211_NWID_LEN + 1];
179 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
182 memset(&na, 0, sizeof(na));
183 strlcpy(na.i_name, interface, sizeof(na.i_name));
184 na.i_type = IEEE80211_IOC_SSID;
185 na.i_data = &info->essid[0];
186 na.i_len = IEEE80211_NWID_LEN + 1;
187 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
192 if (na.i_len <= IEEE80211_NWID_LEN)
195 len = IEEE80211_NWID_LEN + 1;
196 info->essid[len -1] = '\0';
201 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
203 memset(&na, 0, sizeof(na));
204 strlcpy(na.i_name, interface, sizeof(na.i_name));
205 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
207 na.i_len = sizeof(buf);
209 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
218 struct ieee80211req_scan_result *sr;
220 sr = (struct ieee80211req_scan_result *)cp;
221 vp = (u_int8_t *)(sr + 1);
222 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
223 if (!strcmp(network_id, &info->essid[0])) {
224 info->signal_level = sr->isr_rssi;
225 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
226 info->noise_level = sr->isr_noise;
227 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
228 info->quality = sr->isr_intval;
229 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
236 struct ieee80211_bssid bssid;
237 struct ieee80211_nwid nwid;
238 struct ieee80211_nodereq nr;
240 struct ether_addr ea;
242 int s, len, ibssid, inwid;
243 u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
245 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
248 memset(&ifr, 0, sizeof(ifr));
249 ifr.ifr_data = (caddr_t)&nwid;
250 (void)strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
251 inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
253 memset(&bssid, 0, sizeof(bssid));
254 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
255 ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
257 if (ibssid != 0 || inwid != 0) {
264 if (nwid.i_len <= IEEE80211_NWID_LEN)
265 len = nwid.i_len + 1;
267 len = IEEE80211_NWID_LEN + 1;
269 strncpy(&info->essid[0], nwid.i_nwid, len);
270 info->essid[IW_ESSID_MAX_SIZE] = '\0';
271 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
274 /* Signal strength */
276 memset(&zero_bssid, 0, sizeof(zero_bssid));
277 if (ibssid == 0 && memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
278 memcpy(&ea.ether_addr_octet, bssid.i_bssid, sizeof(ea.ether_addr_octet));
280 bzero(&nr, sizeof(nr));
281 bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
282 strlcpy(nr.nr_ifname, interface, sizeof(nr.nr_ifname));
284 if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
286 info->signal_level_max = IEEE80211_NODEREQ_RSSI(&nr);
288 info->signal_level = nr.nr_rssi;
290 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
301 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
303 char *outwalk = buffer;
304 wireless_info_t info;
308 const char *ip_address = get_ip_addr(interface);
309 if (ip_address == NULL) {
310 START_COLOR("color_bad");
311 outwalk += sprintf(outwalk, "%s", format_down);
314 START_COLOR("color_good");
317 if (get_wireless_info(interface, &info)) {
319 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
320 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
324 START_COLOR("color_bad");
327 for (; *walk != '\0'; walk++) {
329 *(outwalk++) = *walk;
333 if (BEGINS_WITH(walk+1, "quality")) {
334 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
335 if (info.quality_max)
336 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
338 outwalk += sprintf(outwalk, "%d", info.quality);
342 walk += strlen("quality");
345 if (BEGINS_WITH(walk+1, "signal")) {
346 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
347 if (info.signal_level_max)
348 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
350 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
354 walk += strlen("signal");
357 if (BEGINS_WITH(walk+1, "noise")) {
358 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
359 if (info.noise_level_max)
360 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
362 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
366 walk += strlen("noise");
369 if (BEGINS_WITH(walk+1, "essid")) {
370 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
371 outwalk += sprintf(outwalk, "%s", info.essid);
374 walk += strlen("essid");
377 if (BEGINS_WITH(walk+1, "ip")) {
378 outwalk += sprintf(outwalk, "%s", ip_address);
379 walk += strlen("ip");
383 if (BEGINS_WITH(walk+1, "bitrate")) {
386 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
388 outwalk += sprintf(outwalk, "%s", br_buffer);
389 walk += strlen("bitrate");
396 OUTPUT_FULL_TEXT(buffer);