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)
58 #define WIRELESS_INFO_FLAG_HAS_FREQUENCY (1 << 4)
60 #define PERCENT_VALUE(value, total) ((int)(value * 100 / (float)total + 0.5f))
64 char essid[IW_ESSID_MAX_SIZE + 1];
76 static int get_wireless_info(const char *interface, wireless_info_t *info) {
77 memset(info, 0, sizeof(wireless_info_t));
80 int skfd = iw_sockets_open();
82 perror("iw_sockets_open");
87 if (iw_get_basic_config(skfd, interface, &wcfg) < 0) {
92 if (wcfg.has_essid && wcfg.essid_on) {
93 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
94 strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE);
95 info->essid[IW_ESSID_MAX_SIZE] = '\0';
99 info->frequency = wcfg.freq;
100 info->flags |= WIRELESS_INFO_FLAG_HAS_FREQUENCY;
103 /* If the function iw_get_stats does not return proper stats, the
104 wifi is considered as down.
105 Since ad-hoc network does not have theses stats, we need to return
106 here for this mode. */
107 if (wcfg.mode == 1) {
112 /* Wireless quality is a relative value in a driver-specific range.
113 Signal and noise level can be either relative or absolute values
114 in dBm. Furthermore, noise and quality can be expressed directly
115 in dBm or in RCPI (802.11k), which we convert to dBm. When those
116 values are expressed directly in dBm, they range from -192 to 63,
117 and since the values are packed into 8 bits, we need to perform
118 8-bit arithmetic on them. Assume absolute values if everything
119 else fails (driver bug). */
122 if (iw_get_range_info(skfd, interface, &range) < 0) {
128 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
133 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
134 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
135 info->quality = stats.qual.qual;
136 info->quality_max = range.max_qual.qual;
137 info->quality_average = range.avg_qual.qual;
138 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
141 if (stats.qual.updated & IW_QUAL_RCPI) {
142 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
143 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
144 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
146 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
147 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
148 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
152 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
153 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
154 info->signal_level = stats.qual.level;
155 if (info->signal_level > 63)
156 info->signal_level -= 256;
157 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
159 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
160 info->noise_level = stats.qual.noise;
161 if (info->noise_level > 63)
162 info->noise_level -= 256;
163 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
167 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
168 info->signal_level = stats.qual.level;
169 info->signal_level_max = range.max_qual.level;
170 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
172 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
173 info->noise_level = stats.qual.noise;
174 info->noise_level_max = range.max_qual.noise;
175 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
181 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
182 info->quality = stats.qual.qual;
183 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
185 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
186 info->quality = stats.qual.level;
187 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
189 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
190 info->quality = stats.qual.noise;
191 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
196 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
197 info->bitrate = wrq.u.bitrate.value;
202 #if defined(__FreeBSD__) || defined(__DragonFly__)
204 uint8_t buf[24 * 1024], *cp;
205 struct ieee80211req na;
206 char network_id[IEEE80211_NWID_LEN + 1];
208 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
211 memset(&na, 0, sizeof(na));
212 strlcpy(na.i_name, interface, sizeof(na.i_name));
213 na.i_type = IEEE80211_IOC_SSID;
214 na.i_data = &info->essid[0];
215 na.i_len = IEEE80211_NWID_LEN + 1;
216 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
221 if (na.i_len <= IEEE80211_NWID_LEN)
224 len = IEEE80211_NWID_LEN + 1;
225 info->essid[len -1] = '\0';
230 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
232 memset(&na, 0, sizeof(na));
233 strlcpy(na.i_name, interface, sizeof(na.i_name));
234 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
236 na.i_len = sizeof(buf);
238 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
247 struct ieee80211req_scan_result *sr;
249 sr = (struct ieee80211req_scan_result *)cp;
250 vp = (u_int8_t *)(sr + 1);
251 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
252 if (!strcmp(network_id, &info->essid[0])) {
253 info->signal_level = sr->isr_rssi;
254 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
255 info->noise_level = sr->isr_noise;
256 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
257 info->quality = sr->isr_intval;
258 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
265 struct ieee80211_bssid bssid;
266 struct ieee80211_nwid nwid;
267 struct ieee80211_nodereq nr;
269 struct ether_addr ea;
271 int s, len, ibssid, inwid;
272 u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
274 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
277 memset(&ifr, 0, sizeof(ifr));
278 ifr.ifr_data = (caddr_t)&nwid;
279 (void)strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
280 inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr);
282 memset(&bssid, 0, sizeof(bssid));
283 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
284 ibssid = ioctl(s, SIOCG80211BSSID, &bssid);
286 if (ibssid != 0 || inwid != 0) {
293 if (nwid.i_len <= IEEE80211_NWID_LEN)
294 len = nwid.i_len + 1;
296 len = IEEE80211_NWID_LEN + 1;
298 strncpy(&info->essid[0], nwid.i_nwid, len);
299 info->essid[IW_ESSID_MAX_SIZE] = '\0';
300 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
303 /* Signal strength */
305 memset(&zero_bssid, 0, sizeof(zero_bssid));
306 if (ibssid == 0 && memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
307 memcpy(&ea.ether_addr_octet, bssid.i_bssid, sizeof(ea.ether_addr_octet));
309 bzero(&nr, sizeof(nr));
310 bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
311 strlcpy(nr.nr_ifname, interface, sizeof(nr.nr_ifname));
313 if (ioctl(s, SIOCG80211NODE, &nr) == 0 && nr.nr_rssi) {
315 info->signal_level_max = IEEE80211_NODEREQ_RSSI(&nr);
317 info->signal_level = nr.nr_rssi;
319 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
330 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
332 char *outwalk = buffer;
333 wireless_info_t info;
337 const char *ip_address = get_ip_addr(interface);
338 if (ip_address == NULL) {
339 START_COLOR("color_bad");
340 outwalk += sprintf(outwalk, "%s", format_down);
344 if (get_wireless_info(interface, &info)) {
346 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
347 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
349 START_COLOR("color_good");
352 START_COLOR("color_bad");
355 for (; *walk != '\0'; walk++) {
357 *(outwalk++) = *walk;
361 if (BEGINS_WITH(walk+1, "quality")) {
362 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
363 if (info.quality_max)
364 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
366 outwalk += sprintf(outwalk, "%d", info.quality);
370 walk += strlen("quality");
373 if (BEGINS_WITH(walk+1, "signal")) {
374 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
375 if (info.signal_level_max)
376 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
378 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
382 walk += strlen("signal");
385 if (BEGINS_WITH(walk+1, "noise")) {
386 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
387 if (info.noise_level_max)
388 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
390 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
394 walk += strlen("noise");
397 if (BEGINS_WITH(walk+1, "essid")) {
398 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
399 outwalk += sprintf(outwalk, "%s", info.essid);
402 walk += strlen("essid");
405 if (BEGINS_WITH(walk+1, "frequency")) {
406 if (info.flags & WIRELESS_INFO_FLAG_HAS_FREQUENCY)
407 outwalk += sprintf(outwalk, "%1.1f GHz", info.frequency / 1e9);
410 walk += strlen("frequency");
413 if (BEGINS_WITH(walk+1, "ip")) {
414 outwalk += sprintf(outwalk, "%s", ip_address);
415 walk += strlen("ip");
419 if (BEGINS_WITH(walk+1, "bitrate")) {
422 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
424 outwalk += sprintf(outwalk, "%s", br_buffer);
425 walk += strlen("bitrate");
432 OUTPUT_FULL_TEXT(buffer);