wifi.c 5.8 KB

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