rfkill.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Linux rfkill helper functions for driver wrappers
  3. * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "includes.h"
  9. #include <fcntl.h>
  10. #include <limits.h>
  11. #include "utils/common.h"
  12. #include "utils/eloop.h"
  13. #include "rfkill.h"
  14. #define RFKILL_EVENT_SIZE_V1 8
  15. struct rfkill_event {
  16. u32 idx;
  17. u8 type;
  18. u8 op;
  19. u8 soft;
  20. u8 hard;
  21. } STRUCT_PACKED;
  22. enum rfkill_operation {
  23. RFKILL_OP_ADD = 0,
  24. RFKILL_OP_DEL,
  25. RFKILL_OP_CHANGE,
  26. RFKILL_OP_CHANGE_ALL,
  27. };
  28. enum rfkill_type {
  29. RFKILL_TYPE_ALL = 0,
  30. RFKILL_TYPE_WLAN,
  31. RFKILL_TYPE_BLUETOOTH,
  32. RFKILL_TYPE_UWB,
  33. RFKILL_TYPE_WIMAX,
  34. RFKILL_TYPE_WWAN,
  35. RFKILL_TYPE_GPS,
  36. RFKILL_TYPE_FM,
  37. NUM_RFKILL_TYPES,
  38. };
  39. struct rfkill_data {
  40. struct rfkill_config *cfg;
  41. int fd;
  42. int blocked;
  43. uint32_t idx;
  44. };
  45. static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
  46. {
  47. struct rfkill_data *rfkill = eloop_ctx;
  48. struct rfkill_event event;
  49. ssize_t len;
  50. int new_blocked;
  51. len = read(rfkill->fd, &event, sizeof(event));
  52. if (len < 0) {
  53. wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
  54. strerror(errno));
  55. return;
  56. }
  57. if (len != RFKILL_EVENT_SIZE_V1) {
  58. wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
  59. "%d (expected %d)",
  60. (int) len, RFKILL_EVENT_SIZE_V1);
  61. return;
  62. }
  63. if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx)
  64. return;
  65. wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
  66. "op=%u soft=%u hard=%u",
  67. event.idx, event.type, event.op, event.soft,
  68. event.hard);
  69. if (event.hard) {
  70. wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
  71. new_blocked = 1;
  72. } else if (event.soft) {
  73. wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
  74. new_blocked = 1;
  75. } else {
  76. wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
  77. new_blocked = 0;
  78. }
  79. if (new_blocked != rfkill->blocked) {
  80. rfkill->blocked = new_blocked;
  81. if (new_blocked)
  82. rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
  83. else
  84. rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
  85. }
  86. }
  87. struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
  88. {
  89. struct rfkill_data *rfkill;
  90. struct rfkill_event event;
  91. ssize_t len;
  92. char *phy = NULL, *rfk_phy;
  93. char buf[24 + IFNAMSIZ + 1];
  94. char buf2[31 + 11 + 1];
  95. int found = 0;
  96. rfkill = os_zalloc(sizeof(*rfkill));
  97. if (rfkill == NULL)
  98. return NULL;
  99. os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211",
  100. cfg->ifname);
  101. phy = realpath(buf, NULL);
  102. if (!phy) {
  103. wpa_printf(MSG_INFO, "rfkill: Cannot get wiphy information");
  104. goto fail;
  105. }
  106. rfkill->cfg = cfg;
  107. rfkill->fd = open("/dev/rfkill", O_RDONLY);
  108. if (rfkill->fd < 0) {
  109. wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
  110. "device");
  111. goto fail;
  112. }
  113. if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
  114. wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
  115. "%s", strerror(errno));
  116. goto fail2;
  117. }
  118. for (;;) {
  119. len = read(rfkill->fd, &event, sizeof(event));
  120. if (len < 0) {
  121. if (errno == EAGAIN)
  122. break; /* No more entries */
  123. wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
  124. strerror(errno));
  125. break;
  126. }
  127. if (len != RFKILL_EVENT_SIZE_V1) {
  128. wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
  129. "%d (expected %d)",
  130. (int) len, RFKILL_EVENT_SIZE_V1);
  131. continue;
  132. }
  133. if (event.op != RFKILL_OP_ADD ||
  134. event.type != RFKILL_TYPE_WLAN)
  135. continue;
  136. os_snprintf(buf2, sizeof(buf2),
  137. "/sys/class/rfkill/rfkill%d/device", event.idx);
  138. rfk_phy = realpath(buf2, NULL);
  139. if (!rfk_phy)
  140. goto fail2;
  141. found = os_strcmp(phy, rfk_phy) == 0;
  142. free(rfk_phy);
  143. if (!found)
  144. continue;
  145. wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
  146. "op=%u soft=%u hard=%u",
  147. event.idx, event.type, event.op, event.soft,
  148. event.hard);
  149. rfkill->idx = event.idx;
  150. if (event.hard) {
  151. wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
  152. rfkill->blocked = 1;
  153. } else if (event.soft) {
  154. wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
  155. rfkill->blocked = 1;
  156. }
  157. break;
  158. }
  159. if (!found)
  160. goto fail2;
  161. free(phy);
  162. eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
  163. return rfkill;
  164. fail2:
  165. close(rfkill->fd);
  166. fail:
  167. os_free(rfkill);
  168. /* use standard free function to match realpath() */
  169. free(phy);
  170. return NULL;
  171. }
  172. void rfkill_deinit(struct rfkill_data *rfkill)
  173. {
  174. if (rfkill == NULL)
  175. return;
  176. if (rfkill->fd >= 0) {
  177. eloop_unregister_read_sock(rfkill->fd);
  178. close(rfkill->fd);
  179. }
  180. os_free(rfkill->cfg);
  181. os_free(rfkill);
  182. }
  183. int rfkill_is_blocked(struct rfkill_data *rfkill)
  184. {
  185. if (rfkill == NULL)
  186. return 0;
  187. return rfkill->blocked;
  188. }