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);
337 if (get_wireless_info(interface, &info)) {
339 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
340 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
342 START_COLOR("color_good");
345 START_COLOR("color_bad");
348 for (; *walk != '\0'; walk++) {
350 *(outwalk++) = *walk;
354 if (BEGINS_WITH(walk+1, "quality")) {
355 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
356 if (info.quality_max)
357 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
359 outwalk += sprintf(outwalk, "%d", info.quality);
363 walk += strlen("quality");
366 if (BEGINS_WITH(walk+1, "signal")) {
367 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
368 if (info.signal_level_max)
369 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
371 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
375 walk += strlen("signal");
378 if (BEGINS_WITH(walk+1, "noise")) {
379 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
380 if (info.noise_level_max)
381 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
383 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
387 walk += strlen("noise");
390 if (BEGINS_WITH(walk+1, "essid")) {
391 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
392 outwalk += sprintf(outwalk, "%s", info.essid);
395 walk += strlen("essid");
398 if (BEGINS_WITH(walk+1, "ip")) {
399 outwalk += sprintf(outwalk, "%s", ip_address);
400 walk += strlen("ip");
404 if (BEGINS_WITH(walk+1, "bitrate")) {
407 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
409 outwalk += sprintf(outwalk, "%s", br_buffer);
410 walk += strlen("bitrate");
417 OUTPUT_FULL_TEXT(buffer);