2 * Linux rfkill helper functions for driver wrappers
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include "utils/common.h"
14 #include "utils/eloop.h"
17 #define RFKILL_EVENT_SIZE_V1 8
27 enum rfkill_operation {
37 RFKILL_TYPE_BLUETOOTH,
48 struct rfkill_config *cfg;
55 static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
57 struct rfkill_data *rfkill = eloop_ctx;
58 struct rfkill_event event;
62 len = read(rfkill->fd, &event, sizeof(event));
64 wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
68 if (len != RFKILL_EVENT_SIZE_V1) {
69 wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
71 (int) len, RFKILL_EVENT_SIZE_V1);
74 if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx)
77 wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
78 "op=%u soft=%u hard=%u",
79 event.idx, event.type, event.op, event.soft,
83 wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
85 } else if (event.soft) {
86 wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
89 wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
93 if (new_blocked != rfkill->blocked) {
94 rfkill->blocked = new_blocked;
96 rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
98 rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
103 struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
105 struct rfkill_data *rfkill;
106 struct rfkill_event event;
108 char *phy = NULL, *rfk_phy;
109 char buf[24 + IFNAMSIZ + 1];
110 char buf2[31 + 11 + 1];
113 rfkill = os_zalloc(sizeof(*rfkill));
117 os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211",
119 phy = realpath(buf, NULL);
121 wpa_printf(MSG_INFO, "rfkill: Cannot get wiphy information");
126 rfkill->fd = open("/dev/rfkill", O_RDONLY);
127 if (rfkill->fd < 0) {
128 wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
133 if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
134 wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
135 "%s", strerror(errno));
140 len = read(rfkill->fd, &event, sizeof(event));
143 break; /* No more entries */
144 wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
148 if (len != RFKILL_EVENT_SIZE_V1) {
149 wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
151 (int) len, RFKILL_EVENT_SIZE_V1);
154 if (event.op != RFKILL_OP_ADD ||
155 event.type != RFKILL_TYPE_WLAN)
158 os_snprintf(buf2, sizeof(buf2),
159 "/sys/class/rfkill/rfkill%d/device", event.idx);
160 rfk_phy = realpath(buf2, NULL);
163 found = os_strcmp(phy, rfk_phy) == 0;
169 wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
170 "op=%u soft=%u hard=%u",
171 event.idx, event.type, event.op, event.soft,
174 rfkill->idx = event.idx;
176 wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
178 } else if (event.soft) {
179 wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
189 eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
197 /* use standard free function to match realpath() */
203 void rfkill_deinit(struct rfkill_data *rfkill)
208 if (rfkill->fd >= 0) {
209 eloop_unregister_read_sock(rfkill->fd);
213 os_free(rfkill->cfg);
218 int rfkill_is_blocked(struct rfkill_data *rfkill)
223 return rfkill->blocked;