123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /*
- * Linux rfkill helper functions for driver wrappers
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
- #include "includes.h"
- #include <fcntl.h>
- #include <limits.h>
- #include "utils/common.h"
- #include "utils/eloop.h"
- #include "rfkill.h"
- #define RFKILL_EVENT_SIZE_V1 8
- struct rfkill_event {
- u32 idx;
- u8 type;
- u8 op;
- u8 soft;
- u8 hard;
- } STRUCT_PACKED;
- enum rfkill_operation {
- RFKILL_OP_ADD = 0,
- RFKILL_OP_DEL,
- RFKILL_OP_CHANGE,
- RFKILL_OP_CHANGE_ALL,
- };
- enum rfkill_type {
- RFKILL_TYPE_ALL = 0,
- RFKILL_TYPE_WLAN,
- RFKILL_TYPE_BLUETOOTH,
- RFKILL_TYPE_UWB,
- RFKILL_TYPE_WIMAX,
- RFKILL_TYPE_WWAN,
- RFKILL_TYPE_GPS,
- RFKILL_TYPE_FM,
- NUM_RFKILL_TYPES,
- };
- struct rfkill_data {
- struct rfkill_config *cfg;
- int fd;
- int blocked;
- uint32_t idx;
- };
- static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
- {
- struct rfkill_data *rfkill = eloop_ctx;
- struct rfkill_event event;
- ssize_t len;
- int new_blocked;
- len = read(rfkill->fd, &event, sizeof(event));
- if (len < 0) {
- wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
- strerror(errno));
- return;
- }
- if (len != RFKILL_EVENT_SIZE_V1) {
- wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
- "%d (expected %d)",
- (int) len, RFKILL_EVENT_SIZE_V1);
- return;
- }
- if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx)
- return;
- wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
- "op=%u soft=%u hard=%u",
- event.idx, event.type, event.op, event.soft,
- event.hard);
- if (event.hard) {
- wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
- new_blocked = 1;
- } else if (event.soft) {
- wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
- new_blocked = 1;
- } else {
- wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
- new_blocked = 0;
- }
- if (new_blocked != rfkill->blocked) {
- rfkill->blocked = new_blocked;
- if (new_blocked)
- rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
- else
- rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
- }
- }
- struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
- {
- struct rfkill_data *rfkill;
- struct rfkill_event event;
- ssize_t len;
- char *phy = NULL, *rfk_phy;
- char buf[24 + IFNAMSIZ + 1];
- char buf2[31 + 11 + 1];
- int found = 0;
- rfkill = os_zalloc(sizeof(*rfkill));
- if (rfkill == NULL)
- return NULL;
- os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211",
- cfg->ifname);
- phy = realpath(buf, NULL);
- if (!phy) {
- wpa_printf(MSG_INFO, "rfkill: Cannot get wiphy information");
- goto fail;
- }
- rfkill->cfg = cfg;
- rfkill->fd = open("/dev/rfkill", O_RDONLY);
- if (rfkill->fd < 0) {
- wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
- "device");
- goto fail;
- }
- if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
- wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
- "%s", strerror(errno));
- goto fail2;
- }
- for (;;) {
- len = read(rfkill->fd, &event, sizeof(event));
- if (len < 0) {
- if (errno == EAGAIN)
- break; /* No more entries */
- wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
- strerror(errno));
- break;
- }
- if (len != RFKILL_EVENT_SIZE_V1) {
- wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
- "%d (expected %d)",
- (int) len, RFKILL_EVENT_SIZE_V1);
- continue;
- }
- if (event.op != RFKILL_OP_ADD ||
- event.type != RFKILL_TYPE_WLAN)
- continue;
- os_snprintf(buf2, sizeof(buf2),
- "/sys/class/rfkill/rfkill%d/device", event.idx);
- rfk_phy = realpath(buf2, NULL);
- if (!rfk_phy)
- goto fail2;
- found = os_strcmp(phy, rfk_phy) == 0;
- free(rfk_phy);
- if (!found)
- continue;
- wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
- "op=%u soft=%u hard=%u",
- event.idx, event.type, event.op, event.soft,
- event.hard);
- rfkill->idx = event.idx;
- if (event.hard) {
- wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
- rfkill->blocked = 1;
- } else if (event.soft) {
- wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
- rfkill->blocked = 1;
- }
- break;
- }
- if (!found)
- goto fail2;
- free(phy);
- eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
- return rfkill;
- fail2:
- close(rfkill->fd);
- fail:
- os_free(rfkill);
- /* use standard free function to match realpath() */
- free(phy);
- return NULL;
- }
- void rfkill_deinit(struct rfkill_data *rfkill)
- {
- if (rfkill == NULL)
- return;
- if (rfkill->fd >= 0) {
- eloop_unregister_read_sock(rfkill->fd);
- close(rfkill->fd);
- }
- os_free(rfkill->cfg);
- os_free(rfkill);
- }
- int rfkill_is_blocked(struct rfkill_data *rfkill)
- {
- if (rfkill == NULL)
- return 0;
- return rfkill->blocked;
- }
|