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 /* If the function iw_get_stats does not return proper stats, the
97 wifi is considered as down.
98 Since ad-hoc network does not have theses stats, we need to return
99 here for this mode. */
100 if (wcfg.mode == 1) {
105 /* Wireless quality is a relative value in a driver-specific range.
106 Signal and noise level can be either relative or absolute values
107 in dBm. Furthermore, noise and quality can be expressed directly
108 in dBm or in RCPI (802.11k), which we convert to dBm. When those
109 values are expressed directly in dBm, they range from -192 to 63,
110 and since the values are packed into 8 bits, we need to perform
111 8-bit arithmetic on them. Assume absolute values if everything
112 else fails (driver bug). */
115 if (iw_get_range_info(skfd, interface, &range) < 0) {
121 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
126 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
127 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
128 info->quality = stats.qual.qual;
129 info->quality_max = range.max_qual.qual;
130 info->quality_average = range.avg_qual.qual;
131 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
134 if (stats.qual.updated & IW_QUAL_RCPI) {
135 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
136 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
137 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
139 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
140 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
141 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
145 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
146 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
147 info->signal_level = stats.qual.level;
148 if (info->signal_level > 63)
149 info->signal_level -= 256;
150 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
152 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
153 info->noise_level = stats.qual.noise;
154 if (info->noise_level > 63)
155 info->noise_level -= 256;
156 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
160 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
161 info->signal_level = stats.qual.level;
162 info->signal_level_max = range.max_qual.level;
163 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
165 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
166 info->noise_level = stats.qual.noise;
167 info->noise_level_max = range.max_qual.noise;
168 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
174 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
175 info->quality = stats.qual.qual;
176 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
178 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
179 info->quality = stats.qual.level;
180 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
182 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
183 info->quality = stats.qual.noise;
184 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
189 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
190 info->bitrate = wrq.u.bitrate.value;
195 #if defined(__FreeBSD__) || defined(__DragonFly__)
197 uint8_t buf[24 * 1024], *cp;
198 struct ieee80211req na;
199 char network_id[IEEE80211_NWID_LEN + 1];
201 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
204 memset(&na, 0, sizeof(na));
205 strlcpy(na.i_name, interface, sizeof(na.i_name));
206 na.i_type = IEEE80211_IOC_SSID;
207 na.i_data = &info->essid[0];
208 na.i_len = IEEE80211_NWID_LEN + 1;
209 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
214 if (na.i_len <= IEEE80211_NWID_LEN)
217 len = IEEE80211_NWID_LEN + 1;
218 info->essid[len -1] = '\0';
223 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
225 memset(&na, 0, sizeof(na));
226 strlcpy(na.i_name, interface, sizeof(na.i_name));
227 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
229 na.i_len = sizeof(buf);
231 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
240 struct ieee80211req_scan_result *sr;
242 sr = (struct ieee80211req_scan_result *)cp;
243 vp = (u_int8_t *)(sr + 1);
244 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
245 if (!strcmp(network_id, &info->essid[0])) {
246 info->signal_level = sr->isr_rssi;
247 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
248 info->noise_level = sr->isr_noise;
249 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
250 info->quality = sr->isr_intval;
251 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
258 struct ieee80211_bssid bssid;
259 struct ieee80211_nwid nwid;
260 struct ieee80211_nodereq nr;
262 struct ether_addr ea;
264 int s, len, ibssid, inwid;
265 u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
267 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
270 memset(&ifr, 0, sizeof(ifr));
271 ifr.ifr_data = (caddr_t)&nwid;
272 (void)strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
273 inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
275 memset(&bssid, 0, sizeof(bssid));
276 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
277 ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
279 if (ibssid != 0 || inwid != 0) {
286 if (nwid.i_len <= IEEE80211_NWID_LEN)
287 len = nwid.i_len + 1;
289 len = IEEE80211_NWID_LEN + 1;
291 strncpy(&info->essid[0], nwid.i_nwid, len);
292 info->essid[IW_ESSID_MAX_SIZE] = '\0';
293 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
296 /* Signal strength */
298 memset(&zero_bssid, 0, sizeof(zero_bssid));
299 if (ibssid == 0 && memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
300 memcpy(&ea.ether_addr_octet, bssid.i_bssid, sizeof(ea.ether_addr_octet));
302 bzero(&nr, sizeof(nr));
303 bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
304 strlcpy(nr.nr_ifname, interface, sizeof(nr.nr_ifname));
306 if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
308 info->signal_level_max = IEEE80211_NODEREQ_RSSI(&nr);
310 info->signal_level = nr.nr_rssi;
312 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
323 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
325 char *outwalk = buffer;
326 wireless_info_t info;
330 const char *ip_address = get_ip_addr(interface);
331 if (ip_address == NULL) {
332 START_COLOR("color_bad");
333 outwalk += sprintf(outwalk, "%s", format_down);
336 START_COLOR("color_good");
339 if (get_wireless_info(interface, &info)) {
341 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
342 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
346 START_COLOR("color_bad");
349 for (; *walk != '\0'; walk++) {
351 *(outwalk++) = *walk;
355 if (BEGINS_WITH(walk+1, "quality")) {
356 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
357 if (info.quality_max)
358 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
360 outwalk += sprintf(outwalk, "%d", info.quality);
364 walk += strlen("quality");
367 if (BEGINS_WITH(walk+1, "signal")) {
368 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
369 if (info.signal_level_max)
370 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
372 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
376 walk += strlen("signal");
379 if (BEGINS_WITH(walk+1, "noise")) {
380 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
381 if (info.noise_level_max)
382 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
384 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
388 walk += strlen("noise");
391 if (BEGINS_WITH(walk+1, "essid")) {
392 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
393 outwalk += sprintf(outwalk, "%s", info.essid);
396 walk += strlen("essid");
399 if (BEGINS_WITH(walk+1, "ip")) {
400 outwalk += sprintf(outwalk, "%s", ip_address);
401 walk += strlen("ip");
405 if (BEGINS_WITH(walk+1, "bitrate")) {
408 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
410 outwalk += sprintf(outwalk, "%s", br_buffer);
411 walk += strlen("bitrate");
418 OUTPUT_FULL_TEXT(buffer);