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
30 #define WIRELESS_INFO_FLAG_HAS_ESSID (1 << 0)
31 #define WIRELESS_INFO_FLAG_HAS_QUALITY (1 << 1)
32 #define WIRELESS_INFO_FLAG_HAS_SIGNAL (1 << 2)
33 #define WIRELESS_INFO_FLAG_HAS_NOISE (1 << 3)
35 #define PERCENT_VALUE(value, total) ((int)(value * 100 / (float)total + 0.5f))
39 char essid[IW_ESSID_MAX_SIZE + 1];
50 static int get_wireless_info(const char *interface, wireless_info_t *info) {
51 memset(info, 0, sizeof(wireless_info_t));
54 int skfd = iw_sockets_open();
56 perror("iw_sockets_open");
61 if (iw_get_basic_config(skfd, interface, &wcfg) < 0) {
66 if (wcfg.has_essid && wcfg.essid_on) {
67 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
68 strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE);
69 info->essid[IW_ESSID_MAX_SIZE] = '\0';
72 /* Wireless quality is a relative value in a driver-specific range.
73 Signal and noise level can be either relative or absolute values
74 in dBm. Furthermore, noise and quality can be expressed directly
75 in dBm or in RCPI (802.11k), which we convert to dBm. When those
76 values are expressed directly in dBm, they range from -192 to 63,
77 and since the values are packed into 8 bits, we need to perform
78 8-bit arithmetic on them. Assume absolute values if everything
79 else fails (driver bug). */
82 if (iw_get_range_info(skfd, interface, &range) < 0) {
88 if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) {
93 if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) {
94 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
95 info->quality = stats.qual.qual;
96 info->quality_max = range.max_qual.qual;
97 info->quality_average = range.avg_qual.qual;
98 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
101 if (stats.qual.updated & IW_QUAL_RCPI) {
102 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
103 info->signal_level = stats.qual.level / 2.0 - 110 + 0.5;
104 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
106 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
107 info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5;
108 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
112 if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) {
113 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
114 info->signal_level = stats.qual.level;
115 if (info->signal_level > 63)
116 info->signal_level -= 256;
117 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
119 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
120 info->noise_level = stats.qual.noise;
121 if (info->noise_level > 63)
122 info->noise_level -= 256;
123 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
127 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
128 info->signal_level = stats.qual.level;
129 info->signal_level_max = range.max_qual.level;
130 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
132 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
133 info->noise_level = stats.qual.noise;
134 info->noise_level_max = range.max_qual.noise;
135 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
141 if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
142 info->quality = stats.qual.qual;
143 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
145 if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) {
146 info->quality = stats.qual.level;
147 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
149 if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) {
150 info->quality = stats.qual.noise;
151 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
156 if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0)
157 info->bitrate = wrq.u.bitrate.value;
164 uint8_t buf[24 * 1024], *cp;
165 struct ieee80211req na;
166 char network_id[IEEE80211_NWID_LEN + 1];
168 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
171 memset(&na, 0, sizeof(na));
172 strlcpy(na.i_name, interface, sizeof(na.i_name));
173 na.i_type = IEEE80211_IOC_SSID;
174 na.i_data = &info->essid[0];
175 na.i_len = IEEE80211_NWID_LEN + 1;
176 if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&na)) == -1) {
181 if (na.i_len <= IEEE80211_NWID_LEN)
184 len = IEEE80211_NWID_LEN + 1;
185 info->essid[len -1] = '\0';
190 info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID;
192 memset(&na, 0, sizeof(na));
193 strlcpy(na.i_name, interface, sizeof(na.i_name));
194 na.i_type = IEEE80211_IOC_SCAN_RESULTS;
196 na.i_len = sizeof(buf);
198 if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) {
207 struct ieee80211req_scan_result *sr;
209 sr = (struct ieee80211req_scan_result *)cp;
210 vp = (u_int8_t *)(sr + 1);
211 strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1);
212 if (!strcmp(network_id, &info->essid[0])) {
213 info->signal_level = sr->isr_rssi;
214 info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL;
215 info->noise_level = sr->isr_noise;
216 info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE;
217 info->quality = sr->isr_intval;
218 info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY;
226 void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down) {
228 char *outwalk = buffer;
229 wireless_info_t info;
233 if (get_wireless_info(interface, &info)) {
235 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY)
236 START_COLOR((info.quality < info.quality_average ? "color_degraded" : "color_good"));
240 START_COLOR("color_bad");
243 for (; *walk != '\0'; walk++) {
245 *(outwalk++) = *walk;
249 if (BEGINS_WITH(walk+1, "quality")) {
250 if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) {
251 if (info.quality_max)
252 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.quality, info.quality_max));
254 outwalk += sprintf(outwalk, "%d", info.quality);
258 walk += strlen("quality");
261 if (BEGINS_WITH(walk+1, "signal")) {
262 if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) {
263 if (info.signal_level_max)
264 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max));
266 outwalk += sprintf(outwalk, "%d dBm", info.signal_level);
270 walk += strlen("signal");
273 if (BEGINS_WITH(walk+1, "noise")) {
274 if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) {
275 if (info.noise_level_max)
276 outwalk += sprintf(outwalk, "%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max));
278 outwalk += sprintf(outwalk, "%d dBm", info.noise_level);
282 walk += strlen("noise");
285 if (BEGINS_WITH(walk+1, "essid")) {
286 if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
287 outwalk += sprintf(outwalk, "%s", info.essid);
290 walk += strlen("essid");
293 if (BEGINS_WITH(walk+1, "ip")) {
294 const char *ip_address = get_ip_addr(interface);
295 outwalk += sprintf(outwalk, "%s", (ip_address ? ip_address : "no IP"));
296 walk += strlen("ip");
300 if (BEGINS_WITH(walk+1, "bitrate")) {
303 iw_print_bitrate(br_buffer, sizeof(br_buffer), info.bitrate);
305 outwalk += sprintf(outwalk, "%s", br_buffer);
306 walk += strlen("bitrate");
312 OUTPUT_FULL_TEXT(buffer);