Branch data Line data Source code
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 : :
53 : 0 : static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
54 : : {
55 : 0 : struct rfkill_data *rfkill = eloop_ctx;
56 : : struct rfkill_event event;
57 : : ssize_t len;
58 : : int new_blocked;
59 : :
60 : 0 : len = read(rfkill->fd, &event, sizeof(event));
61 [ # # ]: 0 : if (len < 0) {
62 : 0 : wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
63 : 0 : strerror(errno));
64 : 0 : return;
65 : : }
66 [ # # ]: 0 : if (len != RFKILL_EVENT_SIZE_V1) {
67 : 0 : wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
68 : : "%d (expected %d)",
69 : : (int) len, RFKILL_EVENT_SIZE_V1);
70 : 0 : return;
71 : : }
72 : 0 : wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
73 : : "op=%u soft=%u hard=%u",
74 : 0 : event.idx, event.type, event.op, event.soft,
75 : 0 : event.hard);
76 [ # # ][ # # ]: 0 : if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN)
77 : 0 : return;
78 : :
79 [ # # ]: 0 : if (event.hard) {
80 : 0 : wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
81 : 0 : new_blocked = 1;
82 [ # # ]: 0 : } else if (event.soft) {
83 : 0 : wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
84 : 0 : new_blocked = 1;
85 : : } else {
86 : 0 : wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
87 : 0 : new_blocked = 0;
88 : : }
89 : :
90 [ # # ]: 0 : if (new_blocked != rfkill->blocked) {
91 : 0 : rfkill->blocked = new_blocked;
92 [ # # ]: 0 : if (new_blocked)
93 : 0 : rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
94 : : else
95 : 0 : rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
96 : : }
97 : : }
98 : :
99 : :
100 : 236 : 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 : 236 : rfkill = os_zalloc(sizeof(*rfkill));
107 [ - + ]: 236 : if (rfkill == NULL)
108 : 0 : return NULL;
109 : :
110 : 236 : rfkill->cfg = cfg;
111 : 236 : rfkill->fd = open("/dev/rfkill", O_RDONLY);
112 [ - + ]: 236 : if (rfkill->fd < 0) {
113 : 0 : wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
114 : : "device");
115 : 0 : goto fail;
116 : : }
117 : :
118 [ - + ]: 236 : if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
119 : 0 : wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
120 : 0 : "%s", strerror(errno));
121 : 0 : goto fail2;
122 : : }
123 : :
124 : : for (;;) {
125 : 1652 : len = read(rfkill->fd, &event, sizeof(event));
126 [ + + ]: 1652 : if (len < 0) {
127 [ + - ]: 236 : if (errno == EAGAIN)
128 : 236 : break; /* No more entries */
129 : 0 : wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
130 : 0 : strerror(errno));
131 : 0 : break;
132 : : }
133 [ - + ]: 1416 : if (len != RFKILL_EVENT_SIZE_V1) {
134 : 0 : wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
135 : : "%d (expected %d)",
136 : : (int) len, RFKILL_EVENT_SIZE_V1);
137 : 0 : continue;
138 : : }
139 : 1416 : wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
140 : : "op=%u soft=%u hard=%u",
141 : 4248 : event.idx, event.type, event.op, event.soft,
142 : 1416 : event.hard);
143 [ - + ][ + - ]: 1416 : if (event.op != RFKILL_OP_ADD ||
144 : 1416 : event.type != RFKILL_TYPE_WLAN)
145 : 0 : continue;
146 [ - + ]: 1416 : if (event.hard) {
147 : 0 : wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
148 : 0 : rfkill->blocked = 1;
149 [ - + ]: 1416 : } else if (event.soft) {
150 : 0 : wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
151 : 0 : rfkill->blocked = 1;
152 : : }
153 : 1416 : }
154 : :
155 : 236 : eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
156 : :
157 : 236 : return rfkill;
158 : :
159 : : fail2:
160 : 0 : close(rfkill->fd);
161 : : fail:
162 : 0 : os_free(rfkill);
163 : 236 : return NULL;
164 : : }
165 : :
166 : :
167 : 236 : void rfkill_deinit(struct rfkill_data *rfkill)
168 : : {
169 [ - + ]: 236 : if (rfkill == NULL)
170 : 236 : return;
171 : :
172 [ + - ]: 236 : if (rfkill->fd >= 0) {
173 : 236 : eloop_unregister_read_sock(rfkill->fd);
174 : 236 : close(rfkill->fd);
175 : : }
176 : :
177 : 236 : os_free(rfkill->cfg);
178 : 236 : os_free(rfkill);
179 : : }
180 : :
181 : :
182 : 0 : int rfkill_is_blocked(struct rfkill_data *rfkill)
183 : : {
184 [ # # ]: 0 : if (rfkill == NULL)
185 : 0 : return 0;
186 : :
187 : 0 : return rfkill->blocked;
188 : : }
|