rfkill.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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 "utils/common.h"
  11. #include "utils/eloop.h"
  12. #include "rfkill.h"
  13. #define RFKILL_EVENT_SIZE_V1 8
  14. struct rfkill_event {
  15. u32 idx;
  16. u8 type;
  17. u8 op;
  18. u8 soft;
  19. u8 hard;
  20. } STRUCT_PACKED;
  21. enum rfkill_operation {
  22. RFKILL_OP_ADD = 0,
  23. RFKILL_OP_DEL,
  24. RFKILL_OP_CHANGE,
  25. RFKILL_OP_CHANGE_ALL,
  26. };
  27. enum rfkill_type {
  28. RFKILL_TYPE_ALL = 0,
  29. RFKILL_TYPE_WLAN,
  30. RFKILL_TYPE_BLUETOOTH,
  31. RFKILL_TYPE_UWB,
  32. RFKILL_TYPE_WIMAX,
  33. RFKILL_TYPE_WWAN,
  34. RFKILL_TYPE_GPS,
  35. RFKILL_TYPE_FM,
  36. NUM_RFKILL_TYPES,
  37. };
  38. struct rfkill_data {
  39. struct rfkill_config *cfg;
  40. int fd;
  41. int blocked;
  42. };
  43. static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
  44. {
  45. struct rfkill_data *rfkill = eloop_ctx;
  46. struct rfkill_event event;
  47. ssize_t len;
  48. int new_blocked;
  49. len = read(rfkill->fd, &event, sizeof(event));
  50. if (len < 0) {
  51. wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
  52. strerror(errno));
  53. return;
  54. }
  55. if (len != RFKILL_EVENT_SIZE_V1) {
  56. wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
  57. "%d (expected %d)",
  58. (int) len, RFKILL_EVENT_SIZE_V1);
  59. return;
  60. }
  61. wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
  62. "op=%u soft=%u hard=%u",
  63. event.idx, event.type, event.op, event.soft,
  64. event.hard);
  65. if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN)
  66. return;
  67. if (event.hard) {
  68. wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
  69. new_blocked = 1;
  70. } else if (event.soft) {
  71. wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
  72. new_blocked = 1;
  73. } else {
  74. wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
  75. new_blocked = 0;
  76. }
  77. if (new_blocked != rfkill->blocked) {
  78. rfkill->blocked = new_blocked;
  79. if (new_blocked)
  80. rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
  81. else
  82. rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
  83. }
  84. }
  85. struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
  86. {
  87. struct rfkill_data *rfkill;
  88. struct rfkill_event event;
  89. ssize_t len;
  90. rfkill = os_zalloc(sizeof(*rfkill));
  91. if (rfkill == NULL)
  92. return NULL;
  93. rfkill->cfg = cfg;
  94. rfkill->fd = open("/dev/rfkill", O_RDONLY);
  95. if (rfkill->fd < 0) {
  96. wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
  97. "device");
  98. goto fail;
  99. }
  100. if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
  101. wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
  102. "%s", strerror(errno));
  103. goto fail2;
  104. }
  105. for (;;) {
  106. len = read(rfkill->fd, &event, sizeof(event));
  107. if (len < 0) {
  108. if (errno == EAGAIN)
  109. break; /* No more entries */
  110. wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
  111. strerror(errno));
  112. break;
  113. }
  114. if (len != RFKILL_EVENT_SIZE_V1) {
  115. wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
  116. "%d (expected %d)",
  117. (int) len, RFKILL_EVENT_SIZE_V1);
  118. continue;
  119. }
  120. wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
  121. "op=%u soft=%u hard=%u",
  122. event.idx, event.type, event.op, event.soft,
  123. event.hard);
  124. if (event.op != RFKILL_OP_ADD ||
  125. event.type != RFKILL_TYPE_WLAN)
  126. continue;
  127. if (event.hard) {
  128. wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
  129. rfkill->blocked = 1;
  130. } else if (event.soft) {
  131. wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
  132. rfkill->blocked = 1;
  133. }
  134. }
  135. eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
  136. return rfkill;
  137. fail2:
  138. close(rfkill->fd);
  139. fail:
  140. os_free(rfkill);
  141. return NULL;
  142. }
  143. void rfkill_deinit(struct rfkill_data *rfkill)
  144. {
  145. if (rfkill == NULL)
  146. return;
  147. if (rfkill->fd >= 0) {
  148. eloop_unregister_read_sock(rfkill->fd);
  149. close(rfkill->fd);
  150. }
  151. os_free(rfkill->cfg);
  152. os_free(rfkill);
  153. }
  154. int rfkill_is_blocked(struct rfkill_data *rfkill)
  155. {
  156. if (rfkill == NULL)
  157. return 0;
  158. return rfkill->blocked;
  159. }