Xinqi Bao's Git

Use the sioctl_open(3) OpenBSD API to access vol
[slstatus.git] / components / wifi.c
1 /* See LICENSE file for copyright and license details. */
2 #include <ifaddrs.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <sys/ioctl.h>
6 #include <sys/socket.h>
7 #include <unistd.h>
8
9 #include "../util.h"
10
11 #define RSSI_TO_PERC(rssi) \
12 rssi >= -50 ? 100 : \
13 (rssi <= -100 ? 0 : \
14 (2 * (rssi + 100)))
15
16 #if defined(__linux__)
17 #include <limits.h>
18 #include <linux/wireless.h>
19
20 const char *
21 wifi_perc(const char *interface)
22 {
23 int cur;
24 size_t i;
25 char *p, *datastart;
26 char path[PATH_MAX];
27 char status[5];
28 FILE *fp;
29
30 if (esnprintf(path, sizeof(path), "/sys/class/net/%s/operstate",
31 interface) < 0) {
32 return NULL;
33 }
34 if (!(fp = fopen(path, "r"))) {
35 warn("fopen '%s':", path);
36 return NULL;
37 }
38 p = fgets(status, 5, fp);
39 fclose(fp);
40 if (!p || strcmp(status, "up\n") != 0) {
41 return NULL;
42 }
43
44 if (!(fp = fopen("/proc/net/wireless", "r"))) {
45 warn("fopen '/proc/net/wireless':");
46 return NULL;
47 }
48
49 for (i = 0; i < 3; i++) {
50 if (!(p = fgets(buf, sizeof(buf) - 1, fp)))
51 break;
52 }
53 fclose(fp);
54 if (i < 2 || !p) {
55 return NULL;
56 }
57
58 if (!(datastart = strstr(buf, interface))) {
59 return NULL;
60 }
61
62 datastart = (datastart+(strlen(interface)+1));
63 sscanf(datastart + 1, " %*d %d %*d %*d\t\t %*d\t "
64 "%*d\t\t%*d\t\t %*d\t %*d\t\t %*d", &cur);
65
66 /* 70 is the max of /proc/net/wireless */
67 return bprintf("%d", (int)((float)cur / 70 * 100));
68 }
69
70 const char *
71 wifi_essid(const char *interface)
72 {
73 static char id[IW_ESSID_MAX_SIZE+1];
74 int sockfd;
75 struct iwreq wreq;
76
77 memset(&wreq, 0, sizeof(struct iwreq));
78 wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
79 if (esnprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s",
80 interface) < 0) {
81 return NULL;
82 }
83
84 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
85 warn("socket 'AF_INET':");
86 return NULL;
87 }
88 wreq.u.essid.pointer = id;
89 if (ioctl(sockfd,SIOCGIWESSID, &wreq) < 0) {
90 warn("ioctl 'SIOCGIWESSID':");
91 close(sockfd);
92 return NULL;
93 }
94
95 close(sockfd);
96
97 if (!strcmp(id, "")) {
98 return NULL;
99 }
100
101 return id;
102 }
103 #elif defined(__OpenBSD__)
104 #include <net/if.h>
105 #include <net/if_media.h>
106 #include <net80211/ieee80211.h>
107 #include <sys/select.h> /* before <sys/ieee80211_ioctl.h> for NBBY */
108 #include <net80211/ieee80211_ioctl.h>
109 #include <stdlib.h>
110 #include <sys/types.h>
111
112 static int
113 load_ieee80211_nodereq(const char *interface, struct ieee80211_nodereq *nr)
114 {
115 struct ieee80211_bssid bssid;
116 int sockfd;
117 uint8_t zero_bssid[IEEE80211_ADDR_LEN];
118
119 memset(&bssid, 0, sizeof(bssid));
120 memset(nr, 0, sizeof(struct ieee80211_nodereq));
121 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
122 warn("socket 'AF_INET':");
123 return 0;
124 }
125 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
126 if ((ioctl(sockfd, SIOCG80211BSSID, &bssid)) < 0) {
127 warn("ioctl 'SIOCG80211BSSID':");
128 close(sockfd);
129 return 0;
130 }
131 memset(&zero_bssid, 0, sizeof(zero_bssid));
132 if (memcmp(bssid.i_bssid, zero_bssid,
133 IEEE80211_ADDR_LEN) == 0) {
134 close(sockfd);
135 return 0;
136 }
137 strlcpy(nr->nr_ifname, interface, sizeof(nr->nr_ifname));
138 memcpy(&nr->nr_macaddr, bssid.i_bssid, sizeof(nr->nr_macaddr));
139 if ((ioctl(sockfd, SIOCG80211NODE, nr)) < 0 && nr->nr_rssi) {
140 warn("ioctl 'SIOCG80211NODE':");
141 close(sockfd);
142 return 0;
143 }
144
145 return close(sockfd), 1;
146 }
147
148 const char *
149 wifi_perc(const char *interface)
150 {
151 struct ieee80211_nodereq nr;
152 int q;
153
154 if (load_ieee80211_nodereq(interface, &nr)) {
155 if (nr.nr_max_rssi) {
156 q = IEEE80211_NODEREQ_RSSI(&nr);
157 } else {
158 q = RSSI_TO_PERC(nr.nr_rssi);
159 }
160 return bprintf("%d", q);
161 }
162
163 return NULL;
164 }
165
166 const char *
167 wifi_essid(const char *interface)
168 {
169 struct ieee80211_nodereq nr;
170
171 if (load_ieee80211_nodereq(interface, &nr)) {
172 return bprintf("%s", nr.nr_nwid);
173 }
174
175 return NULL;
176 }
177 #elif defined(__FreeBSD__)
178 #include <net/if.h>
179 #include <net80211/ieee80211_ioctl.h>
180
181 int
182 load_ieee80211req(int sock, const char *interface, void *data, int type, size_t *len)
183 {
184 char warn_buf[256];
185 struct ieee80211req ireq;
186 memset(&ireq, 0, sizeof(ireq));
187 ireq.i_type = type;
188 ireq.i_data = (caddr_t) data;
189 ireq.i_len = *len;
190
191 strlcpy(ireq.i_name, interface, sizeof(ireq.i_name));
192 if (ioctl(sock, SIOCG80211, &ireq) < 0) {
193 snprintf(warn_buf, sizeof(warn_buf),
194 "ioctl: 'SIOCG80211': %d", type);
195 warn(warn_buf);
196 return 0;
197 }
198
199 *len = ireq.i_len;
200 return 1;
201 }
202
203 const char *
204 wifi_perc(const char *interface)
205 {
206 union {
207 struct ieee80211req_sta_req sta;
208 uint8_t buf[24 * 1024];
209 } info;
210 uint8_t bssid[IEEE80211_ADDR_LEN];
211 int rssi_dbm;
212 int sockfd;
213 size_t len;
214 const char *fmt;
215
216 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
217 warn("socket 'AF_INET':");
218 return NULL;
219 }
220
221 /* Retreive MAC address of interface */
222 len = IEEE80211_ADDR_LEN;
223 fmt = NULL;
224 if (load_ieee80211req(sockfd, interface, &bssid, IEEE80211_IOC_BSSID, &len))
225 {
226 /* Retrieve info on station with above BSSID */
227 memset(&info, 0, sizeof(info));
228 memcpy(info.sta.is_u.macaddr, bssid, sizeof(bssid));
229
230 len = sizeof(info);
231 if (load_ieee80211req(sockfd, interface, &info, IEEE80211_IOC_STA_INFO, &len)) {
232 rssi_dbm = info.sta.info[0].isi_noise +
233 info.sta.info[0].isi_rssi / 2;
234
235 fmt = bprintf("%d", RSSI_TO_PERC(rssi_dbm));
236 }
237 }
238
239 close(sockfd);
240 return fmt;
241 }
242
243 const char *
244 wifi_essid(const char *interface)
245 {
246 char ssid[IEEE80211_NWID_LEN + 1];
247 size_t len;
248 int sockfd;
249 const char *fmt;
250
251 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
252 warn("socket 'AF_INET':");
253 return NULL;
254 }
255
256 fmt = NULL;
257 len = sizeof(ssid);
258 memset(&ssid, 0, len);
259 if (load_ieee80211req(sockfd, interface, &ssid, IEEE80211_IOC_SSID, &len )) {
260 if (len < sizeof(ssid))
261 len += 1;
262 else
263 len = sizeof(ssid);
264
265 ssid[len - 1] = '\0';
266 fmt = bprintf("%s", ssid);
267 }
268
269 close(sockfd);
270 return fmt;
271 }
272 #endif