1 /*
2  * WPA Supplicant / Zephyr socket pair -based control interface
3  * Copyright (c) 2022, 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 "ctrl_iface_zephyr.h"
10 
wpa_supplicant_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)11 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
12 					      void *sock_ctx)
13 {
14 	struct wpa_supplicant *wpa_s = eloop_ctx;
15 	char *buf, *pos;
16 	int res;
17 	char *reply = NULL;
18 	size_t reply_len = 0;
19 
20 	buf = os_zalloc(CTRL_IFACE_MAX_LEN + 1);
21 	if (!buf)
22 		return;
23 	res = recv(sock, buf, CTRL_IFACE_MAX_LEN, 0);
24 	if (res < 0) {
25 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
26 			   strerror(errno));
27 		os_free(buf);
28 		return;
29 	}
30 
31 	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
32 		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
33 		os_free(buf);
34 		return;
35 	}
36 	buf[res] = '\0';
37 
38 	pos = buf;
39 	while (*pos == ' ')
40 		pos++;
41 
42 	reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
43 							&reply_len);
44 
45 	if (reply) {
46 		send(sock, reply, reply_len, 0);
47 		os_free(reply);
48 	} else if (reply_len == 1) {
49 		send(sock, "FAIL\n", 5, 0);
50 	} else if (reply_len == 2) {
51 		send(sock, "OK\n", 3, 0);
52 	}
53 
54 	os_free(buf);
55 }
56 
57 
58 struct ctrl_iface_priv *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant * wpa_s)59 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
60 {
61 	struct ctrl_iface_priv *priv;
62 	int ret;
63 
64 	priv = os_zalloc(sizeof(*priv));
65 	if (priv == NULL)
66 		return NULL;
67 	priv->wpa_s = wpa_s;
68 	memset(priv->sock_pair, -1, sizeof(priv->sock_pair));
69 
70 	if (wpa_s->conf->ctrl_interface == NULL)
71 		return priv;
72 
73 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, priv->sock_pair);
74 	if (ret != 0) {
75 		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
76 		goto fail;
77 	}
78 
79 	os_free(wpa_s->conf->ctrl_interface);
80 	wpa_s->conf->ctrl_interface = os_strdup("zephyr:");
81 	if (!wpa_s->conf->ctrl_interface) {
82 		wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
83 		goto fail;
84 	}
85 
86 	eloop_register_read_sock(priv->sock_pair[1], wpa_supplicant_ctrl_iface_receive,
87 				 wpa_s, priv);
88 
89 	return priv;
90 
91 fail:
92 	if (priv->sock_pair[0] >= 0)
93 		close(priv->sock_pair[0]);
94 	if (priv->sock_pair[1] >= 0)
95 		close(priv->sock_pair[1]);
96 	os_free(priv);
97 	return NULL;
98 }
99 
100 
wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant * wpa_s,struct ctrl_iface_priv * priv)101 void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
102 				      struct ctrl_iface_priv *priv)
103 {
104 	if (!priv)
105 		return;
106 
107 	if (priv->sock_pair[0] > -1) {
108 		eloop_unregister_read_sock(priv->sock_pair[0]);
109 		close(priv->sock_pair[0]);
110 		priv->sock_pair[0] = -1;
111 	}
112 
113 	if (priv->sock_pair[1] >= 0)
114 		close(priv->sock_pair[1]);
115 
116 	os_free(priv);
117 }
118 
119 void
wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv * priv)120 wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
121 {
122 }
123 
124 /* Global control interface */
125 
wpa_supplicant_global_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)126 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
127 					      void *sock_ctx)
128 {
129 	struct wpa_global *global = eloop_ctx;
130 	char *buf, *pos;
131 	int res;
132 	char *reply = NULL;
133 	size_t reply_len = 0;
134 
135 	buf = os_zalloc(CTRL_IFACE_MAX_LEN + 1);
136 	if (!buf)
137 		return;
138 	res = recv(sock, buf, CTRL_IFACE_MAX_LEN, 0);
139 	if (res < 0) {
140 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
141 			   strerror(errno));
142 		os_free(buf);
143 		return;
144 	}
145 
146 	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
147 		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
148 		os_free(buf);
149 		return;
150 	}
151 	buf[res] = '\0';
152 
153 	pos = buf;
154 	while (*pos == ' ')
155 		pos++;
156 
157 	reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
158 							&reply_len);
159 
160 	if (reply) {
161 		send(sock, reply, reply_len, 0);
162 		os_free(reply);
163 	} else if (reply_len == 1) {
164 		send(sock, "FAIL\n", 5, 0);
165 	} else if (reply_len == 2) {
166 		send(sock, "OK\n", 3, 0);
167 	}
168 
169 	os_free(buf);
170 }
171 struct ctrl_iface_global_priv *
wpa_supplicant_global_ctrl_iface_init(struct wpa_global * global)172 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
173 {
174 	struct ctrl_iface_global_priv *priv;
175 	int ret;
176 
177 	priv = os_zalloc(sizeof(*priv));
178 	if (priv == NULL)
179 		return NULL;
180 	priv->global = global;
181 	memset(priv->sock_pair, -1, sizeof(priv->sock_pair));
182 
183 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, priv->sock_pair);
184 	if (ret != 0) {
185 		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
186 		goto fail;
187 	}
188 
189 	os_free(global->params.ctrl_interface);
190 	global->params.ctrl_interface = os_strdup("g_zephyr:");
191 	if (!global->params.ctrl_interface) {
192 		wpa_printf(MSG_ERROR, "Failed to malloc global ctrl_interface\n");
193 		goto fail;
194 	}
195 
196 	eloop_register_read_sock(priv->sock_pair[1], wpa_supplicant_global_ctrl_iface_receive,
197 				 global, priv);
198 
199 	return priv;
200 
201 fail:
202 	if (priv->sock_pair[0] >= 0)
203 		close(priv->sock_pair[0]);
204 	if (priv->sock_pair[1] >= 0)
205 		close(priv->sock_pair[1]);
206 	os_free(priv);
207 	return NULL;
208 }
209 
210 void
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv * priv)211 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
212 {
213 	if (!priv)
214 		return;
215 
216 	if (priv->sock_pair[0] > -1) {
217 		eloop_unregister_read_sock(priv->sock_pair[0]);
218 		close(priv->sock_pair[0]);
219 		priv->sock_pair[0] = -1;
220 	}
221 
222 	if (priv->sock_pair[1] >= 0)
223 		close(priv->sock_pair[1]);
224 
225 	os_free(priv);
226 }
227