xref: /aosp_15_r20/external/wpa_supplicant_8/src/drivers/rfkill.c (revision 03f9172ca588f91df233974f4258bab95191f931)
1*03f9172cSAndroid Build Coastguard Worker /*
2*03f9172cSAndroid Build Coastguard Worker  * Linux rfkill helper functions for driver wrappers
3*03f9172cSAndroid Build Coastguard Worker  * Copyright (c) 2010, Jouni Malinen <[email protected]>
4*03f9172cSAndroid Build Coastguard Worker  *
5*03f9172cSAndroid Build Coastguard Worker  * This software may be distributed under the terms of the BSD license.
6*03f9172cSAndroid Build Coastguard Worker  * See README for more details.
7*03f9172cSAndroid Build Coastguard Worker  */
8*03f9172cSAndroid Build Coastguard Worker 
9*03f9172cSAndroid Build Coastguard Worker #include "includes.h"
10*03f9172cSAndroid Build Coastguard Worker #include <fcntl.h>
11*03f9172cSAndroid Build Coastguard Worker #include <limits.h>
12*03f9172cSAndroid Build Coastguard Worker 
13*03f9172cSAndroid Build Coastguard Worker #include "utils/common.h"
14*03f9172cSAndroid Build Coastguard Worker #include "utils/eloop.h"
15*03f9172cSAndroid Build Coastguard Worker #include "rfkill.h"
16*03f9172cSAndroid Build Coastguard Worker 
17*03f9172cSAndroid Build Coastguard Worker #define RFKILL_EVENT_SIZE_V1 8
18*03f9172cSAndroid Build Coastguard Worker 
19*03f9172cSAndroid Build Coastguard Worker struct rfkill_event {
20*03f9172cSAndroid Build Coastguard Worker 	u32 idx;
21*03f9172cSAndroid Build Coastguard Worker 	u8 type;
22*03f9172cSAndroid Build Coastguard Worker 	u8 op;
23*03f9172cSAndroid Build Coastguard Worker 	u8 soft;
24*03f9172cSAndroid Build Coastguard Worker 	u8 hard;
25*03f9172cSAndroid Build Coastguard Worker } STRUCT_PACKED;
26*03f9172cSAndroid Build Coastguard Worker 
27*03f9172cSAndroid Build Coastguard Worker enum rfkill_operation {
28*03f9172cSAndroid Build Coastguard Worker 	RFKILL_OP_ADD = 0,
29*03f9172cSAndroid Build Coastguard Worker 	RFKILL_OP_DEL,
30*03f9172cSAndroid Build Coastguard Worker 	RFKILL_OP_CHANGE,
31*03f9172cSAndroid Build Coastguard Worker 	RFKILL_OP_CHANGE_ALL,
32*03f9172cSAndroid Build Coastguard Worker };
33*03f9172cSAndroid Build Coastguard Worker 
34*03f9172cSAndroid Build Coastguard Worker enum rfkill_type {
35*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_ALL = 0,
36*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_WLAN,
37*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_BLUETOOTH,
38*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_UWB,
39*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_WIMAX,
40*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_WWAN,
41*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_GPS,
42*03f9172cSAndroid Build Coastguard Worker 	RFKILL_TYPE_FM,
43*03f9172cSAndroid Build Coastguard Worker 	NUM_RFKILL_TYPES,
44*03f9172cSAndroid Build Coastguard Worker };
45*03f9172cSAndroid Build Coastguard Worker 
46*03f9172cSAndroid Build Coastguard Worker 
47*03f9172cSAndroid Build Coastguard Worker struct rfkill_data {
48*03f9172cSAndroid Build Coastguard Worker 	struct rfkill_config *cfg;
49*03f9172cSAndroid Build Coastguard Worker 	int fd;
50*03f9172cSAndroid Build Coastguard Worker 	int blocked;
51*03f9172cSAndroid Build Coastguard Worker 	uint32_t idx;
52*03f9172cSAndroid Build Coastguard Worker };
53*03f9172cSAndroid Build Coastguard Worker 
54*03f9172cSAndroid Build Coastguard Worker 
rfkill_receive(int sock,void * eloop_ctx,void * sock_ctx)55*03f9172cSAndroid Build Coastguard Worker static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
56*03f9172cSAndroid Build Coastguard Worker {
57*03f9172cSAndroid Build Coastguard Worker 	struct rfkill_data *rfkill = eloop_ctx;
58*03f9172cSAndroid Build Coastguard Worker 	struct rfkill_event event;
59*03f9172cSAndroid Build Coastguard Worker 	ssize_t len;
60*03f9172cSAndroid Build Coastguard Worker 	int new_blocked;
61*03f9172cSAndroid Build Coastguard Worker 
62*03f9172cSAndroid Build Coastguard Worker 	len = read(rfkill->fd, &event, sizeof(event));
63*03f9172cSAndroid Build Coastguard Worker 	if (len < 0) {
64*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
65*03f9172cSAndroid Build Coastguard Worker 			   strerror(errno));
66*03f9172cSAndroid Build Coastguard Worker 		return;
67*03f9172cSAndroid Build Coastguard Worker 	}
68*03f9172cSAndroid Build Coastguard Worker 	if (len != RFKILL_EVENT_SIZE_V1) {
69*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
70*03f9172cSAndroid Build Coastguard Worker 			   "%d (expected %d)",
71*03f9172cSAndroid Build Coastguard Worker 			   (int) len, RFKILL_EVENT_SIZE_V1);
72*03f9172cSAndroid Build Coastguard Worker 		return;
73*03f9172cSAndroid Build Coastguard Worker 	}
74*03f9172cSAndroid Build Coastguard Worker 	if (event.op != RFKILL_OP_CHANGE || event.idx != rfkill->idx)
75*03f9172cSAndroid Build Coastguard Worker 		return;
76*03f9172cSAndroid Build Coastguard Worker 
77*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d "
78*03f9172cSAndroid Build Coastguard Worker 		   "op=%u soft=%u hard=%u",
79*03f9172cSAndroid Build Coastguard Worker 		   event.idx, event.type, event.op, event.soft,
80*03f9172cSAndroid Build Coastguard Worker 		   event.hard);
81*03f9172cSAndroid Build Coastguard Worker 
82*03f9172cSAndroid Build Coastguard Worker 	if (event.hard) {
83*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
84*03f9172cSAndroid Build Coastguard Worker 		new_blocked = 1;
85*03f9172cSAndroid Build Coastguard Worker 	} else if (event.soft) {
86*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
87*03f9172cSAndroid Build Coastguard Worker 		new_blocked = 1;
88*03f9172cSAndroid Build Coastguard Worker 	} else {
89*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
90*03f9172cSAndroid Build Coastguard Worker 		new_blocked = 0;
91*03f9172cSAndroid Build Coastguard Worker 	}
92*03f9172cSAndroid Build Coastguard Worker 
93*03f9172cSAndroid Build Coastguard Worker 	if (new_blocked != rfkill->blocked) {
94*03f9172cSAndroid Build Coastguard Worker 		rfkill->blocked = new_blocked;
95*03f9172cSAndroid Build Coastguard Worker 		if (new_blocked)
96*03f9172cSAndroid Build Coastguard Worker 			rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
97*03f9172cSAndroid Build Coastguard Worker 		else
98*03f9172cSAndroid Build Coastguard Worker 			rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
99*03f9172cSAndroid Build Coastguard Worker 	}
100*03f9172cSAndroid Build Coastguard Worker }
101*03f9172cSAndroid Build Coastguard Worker 
102*03f9172cSAndroid Build Coastguard Worker 
rfkill_init(struct rfkill_config * cfg)103*03f9172cSAndroid Build Coastguard Worker struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
104*03f9172cSAndroid Build Coastguard Worker {
105*03f9172cSAndroid Build Coastguard Worker 	struct rfkill_data *rfkill;
106*03f9172cSAndroid Build Coastguard Worker 	struct rfkill_event event;
107*03f9172cSAndroid Build Coastguard Worker 	ssize_t len;
108*03f9172cSAndroid Build Coastguard Worker 	char *phy = NULL, *rfk_phy;
109*03f9172cSAndroid Build Coastguard Worker 	char buf[24 + IFNAMSIZ + 1];
110*03f9172cSAndroid Build Coastguard Worker 	char buf2[31 + 11 + 1];
111*03f9172cSAndroid Build Coastguard Worker 	int found = 0;
112*03f9172cSAndroid Build Coastguard Worker 
113*03f9172cSAndroid Build Coastguard Worker 	rfkill = os_zalloc(sizeof(*rfkill));
114*03f9172cSAndroid Build Coastguard Worker 	if (rfkill == NULL)
115*03f9172cSAndroid Build Coastguard Worker 		return NULL;
116*03f9172cSAndroid Build Coastguard Worker 
117*03f9172cSAndroid Build Coastguard Worker 	os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211",
118*03f9172cSAndroid Build Coastguard Worker 		    cfg->ifname);
119*03f9172cSAndroid Build Coastguard Worker 	phy = realpath(buf, NULL);
120*03f9172cSAndroid Build Coastguard Worker 	if (!phy) {
121*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO, "rfkill: Cannot get wiphy information");
122*03f9172cSAndroid Build Coastguard Worker 		goto fail;
123*03f9172cSAndroid Build Coastguard Worker 	}
124*03f9172cSAndroid Build Coastguard Worker 
125*03f9172cSAndroid Build Coastguard Worker 	rfkill->cfg = cfg;
126*03f9172cSAndroid Build Coastguard Worker 	rfkill->fd = open("/dev/rfkill", O_RDONLY);
127*03f9172cSAndroid Build Coastguard Worker 	if (rfkill->fd < 0) {
128*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
129*03f9172cSAndroid Build Coastguard Worker 			   "device");
130*03f9172cSAndroid Build Coastguard Worker 		goto fail;
131*03f9172cSAndroid Build Coastguard Worker 	}
132*03f9172cSAndroid Build Coastguard Worker 
133*03f9172cSAndroid Build Coastguard Worker 	if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
134*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
135*03f9172cSAndroid Build Coastguard Worker 			   "%s", strerror(errno));
136*03f9172cSAndroid Build Coastguard Worker 		goto fail2;
137*03f9172cSAndroid Build Coastguard Worker 	}
138*03f9172cSAndroid Build Coastguard Worker 
139*03f9172cSAndroid Build Coastguard Worker 	for (;;) {
140*03f9172cSAndroid Build Coastguard Worker 		len = read(rfkill->fd, &event, sizeof(event));
141*03f9172cSAndroid Build Coastguard Worker 		if (len < 0) {
142*03f9172cSAndroid Build Coastguard Worker 			if (errno == EAGAIN)
143*03f9172cSAndroid Build Coastguard Worker 				break; /* No more entries */
144*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
145*03f9172cSAndroid Build Coastguard Worker 				   strerror(errno));
146*03f9172cSAndroid Build Coastguard Worker 			break;
147*03f9172cSAndroid Build Coastguard Worker 		}
148*03f9172cSAndroid Build Coastguard Worker 		if (len != RFKILL_EVENT_SIZE_V1) {
149*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
150*03f9172cSAndroid Build Coastguard Worker 				   "%d (expected %d)",
151*03f9172cSAndroid Build Coastguard Worker 				   (int) len, RFKILL_EVENT_SIZE_V1);
152*03f9172cSAndroid Build Coastguard Worker 			continue;
153*03f9172cSAndroid Build Coastguard Worker 		}
154*03f9172cSAndroid Build Coastguard Worker 		if (event.op != RFKILL_OP_ADD ||
155*03f9172cSAndroid Build Coastguard Worker 		    event.type != RFKILL_TYPE_WLAN)
156*03f9172cSAndroid Build Coastguard Worker 			continue;
157*03f9172cSAndroid Build Coastguard Worker 
158*03f9172cSAndroid Build Coastguard Worker 		os_snprintf(buf2, sizeof(buf2),
159*03f9172cSAndroid Build Coastguard Worker 			    "/sys/class/rfkill/rfkill%d/device", event.idx);
160*03f9172cSAndroid Build Coastguard Worker 		rfk_phy = realpath(buf2, NULL);
161*03f9172cSAndroid Build Coastguard Worker 		if (!rfk_phy)
162*03f9172cSAndroid Build Coastguard Worker 			goto fail2;
163*03f9172cSAndroid Build Coastguard Worker 		found = os_strcmp(phy, rfk_phy) == 0;
164*03f9172cSAndroid Build Coastguard Worker 		free(rfk_phy);
165*03f9172cSAndroid Build Coastguard Worker 
166*03f9172cSAndroid Build Coastguard Worker 		if (!found)
167*03f9172cSAndroid Build Coastguard Worker 			continue;
168*03f9172cSAndroid Build Coastguard Worker 
169*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d "
170*03f9172cSAndroid Build Coastguard Worker 			   "op=%u soft=%u hard=%u",
171*03f9172cSAndroid Build Coastguard Worker 			   event.idx, event.type, event.op, event.soft,
172*03f9172cSAndroid Build Coastguard Worker 			   event.hard);
173*03f9172cSAndroid Build Coastguard Worker 
174*03f9172cSAndroid Build Coastguard Worker 		rfkill->idx = event.idx;
175*03f9172cSAndroid Build Coastguard Worker 		if (event.hard) {
176*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
177*03f9172cSAndroid Build Coastguard Worker 			rfkill->blocked = 1;
178*03f9172cSAndroid Build Coastguard Worker 		} else if (event.soft) {
179*03f9172cSAndroid Build Coastguard Worker 			wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
180*03f9172cSAndroid Build Coastguard Worker 			rfkill->blocked = 1;
181*03f9172cSAndroid Build Coastguard Worker 		}
182*03f9172cSAndroid Build Coastguard Worker 		break;
183*03f9172cSAndroid Build Coastguard Worker 	}
184*03f9172cSAndroid Build Coastguard Worker 
185*03f9172cSAndroid Build Coastguard Worker 	if (!found)
186*03f9172cSAndroid Build Coastguard Worker 		goto fail2;
187*03f9172cSAndroid Build Coastguard Worker 
188*03f9172cSAndroid Build Coastguard Worker 	free(phy);
189*03f9172cSAndroid Build Coastguard Worker 	eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
190*03f9172cSAndroid Build Coastguard Worker 
191*03f9172cSAndroid Build Coastguard Worker 	return rfkill;
192*03f9172cSAndroid Build Coastguard Worker 
193*03f9172cSAndroid Build Coastguard Worker fail2:
194*03f9172cSAndroid Build Coastguard Worker 	close(rfkill->fd);
195*03f9172cSAndroid Build Coastguard Worker fail:
196*03f9172cSAndroid Build Coastguard Worker 	os_free(rfkill);
197*03f9172cSAndroid Build Coastguard Worker 	/* use standard free function to match realpath() */
198*03f9172cSAndroid Build Coastguard Worker 	free(phy);
199*03f9172cSAndroid Build Coastguard Worker 	return NULL;
200*03f9172cSAndroid Build Coastguard Worker }
201*03f9172cSAndroid Build Coastguard Worker 
202*03f9172cSAndroid Build Coastguard Worker 
rfkill_deinit(struct rfkill_data * rfkill)203*03f9172cSAndroid Build Coastguard Worker void rfkill_deinit(struct rfkill_data *rfkill)
204*03f9172cSAndroid Build Coastguard Worker {
205*03f9172cSAndroid Build Coastguard Worker 	if (rfkill == NULL)
206*03f9172cSAndroid Build Coastguard Worker 		return;
207*03f9172cSAndroid Build Coastguard Worker 
208*03f9172cSAndroid Build Coastguard Worker 	if (rfkill->fd >= 0) {
209*03f9172cSAndroid Build Coastguard Worker 		eloop_unregister_read_sock(rfkill->fd);
210*03f9172cSAndroid Build Coastguard Worker 		close(rfkill->fd);
211*03f9172cSAndroid Build Coastguard Worker 	}
212*03f9172cSAndroid Build Coastguard Worker 
213*03f9172cSAndroid Build Coastguard Worker 	os_free(rfkill->cfg);
214*03f9172cSAndroid Build Coastguard Worker 	os_free(rfkill);
215*03f9172cSAndroid Build Coastguard Worker }
216*03f9172cSAndroid Build Coastguard Worker 
217*03f9172cSAndroid Build Coastguard Worker 
rfkill_is_blocked(struct rfkill_data * rfkill)218*03f9172cSAndroid Build Coastguard Worker int rfkill_is_blocked(struct rfkill_data *rfkill)
219*03f9172cSAndroid Build Coastguard Worker {
220*03f9172cSAndroid Build Coastguard Worker 	if (rfkill == NULL)
221*03f9172cSAndroid Build Coastguard Worker 		return 0;
222*03f9172cSAndroid Build Coastguard Worker 
223*03f9172cSAndroid Build Coastguard Worker 	return rfkill->blocked;
224*03f9172cSAndroid Build Coastguard Worker }
225