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 141 : static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
54 : {
55 141 : struct rfkill_data *rfkill = eloop_ctx;
56 : struct rfkill_event event;
57 : ssize_t len;
58 : int new_blocked;
59 :
60 141 : len = read(rfkill->fd, &event, sizeof(event));
61 141 : if (len < 0) {
62 0 : wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
63 0 : strerror(errno));
64 0 : return;
65 : }
66 141 : 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 564 : wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
73 : "op=%u soft=%u hard=%u",
74 423 : event.idx, event.type, event.op, event.soft,
75 141 : event.hard);
76 141 : if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN)
77 80 : return;
78 :
79 61 : if (event.hard) {
80 0 : wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
81 0 : new_blocked = 1;
82 61 : } else if (event.soft) {
83 31 : wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
84 31 : new_blocked = 1;
85 : } else {
86 30 : wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
87 30 : new_blocked = 0;
88 : }
89 :
90 61 : if (new_blocked != rfkill->blocked) {
91 55 : rfkill->blocked = new_blocked;
92 55 : if (new_blocked)
93 28 : rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
94 : else
95 27 : rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
96 : }
97 : }
98 :
99 :
100 1115 : 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 1115 : rfkill = os_zalloc(sizeof(*rfkill));
107 1115 : if (rfkill == NULL)
108 4 : return NULL;
109 :
110 1111 : rfkill->cfg = cfg;
111 1111 : rfkill->fd = open("/dev/rfkill", O_RDONLY);
112 1111 : if (rfkill->fd < 0) {
113 0 : wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
114 : "device");
115 0 : goto fail;
116 : }
117 :
118 1111 : 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 7810 : len = read(rfkill->fd, &event, sizeof(event));
126 7810 : if (len < 0) {
127 1111 : if (errno == EAGAIN)
128 1111 : break; /* No more entries */
129 0 : wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
130 0 : strerror(errno));
131 0 : break;
132 : }
133 6699 : 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 26796 : wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
140 : "op=%u soft=%u hard=%u",
141 20097 : event.idx, event.type, event.op, event.soft,
142 6699 : event.hard);
143 13398 : if (event.op != RFKILL_OP_ADD ||
144 6699 : event.type != RFKILL_TYPE_WLAN)
145 0 : continue;
146 6699 : if (event.hard) {
147 0 : wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
148 0 : rfkill->blocked = 1;
149 6699 : } else if (event.soft) {
150 2 : wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
151 2 : rfkill->blocked = 1;
152 : }
153 6699 : }
154 :
155 1111 : eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
156 :
157 1111 : return rfkill;
158 :
159 : fail2:
160 0 : close(rfkill->fd);
161 : fail:
162 0 : os_free(rfkill);
163 0 : return NULL;
164 : }
165 :
166 :
167 1119 : void rfkill_deinit(struct rfkill_data *rfkill)
168 : {
169 1119 : if (rfkill == NULL)
170 1127 : return;
171 :
172 1111 : if (rfkill->fd >= 0) {
173 1111 : eloop_unregister_read_sock(rfkill->fd);
174 1111 : close(rfkill->fd);
175 : }
176 :
177 1111 : os_free(rfkill->cfg);
178 1111 : os_free(rfkill);
179 : }
180 :
181 :
182 1102 : int rfkill_is_blocked(struct rfkill_data *rfkill)
183 : {
184 1102 : if (rfkill == NULL)
185 4 : return 0;
186 :
187 1098 : return rfkill->blocked;
188 : }
|