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