1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * wpa_supplicant ctrl_iface helpers
3e5b75505Sopenharmony_ci * Copyright (c) 2010-2011, Atheros Communications, Inc.
4e5b75505Sopenharmony_ci * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
5e5b75505Sopenharmony_ci *
6e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
7e5b75505Sopenharmony_ci * See README for more details.
8e5b75505Sopenharmony_ci */
9e5b75505Sopenharmony_ci
10e5b75505Sopenharmony_ci#include "includes.h"
11e5b75505Sopenharmony_ci#include <time.h>
12e5b75505Sopenharmony_ci
13e5b75505Sopenharmony_ci#include "common.h"
14e5b75505Sopenharmony_ci#include "wpa_ctrl.h"
15e5b75505Sopenharmony_ci#include "wpa_helpers.h"
16e5b75505Sopenharmony_ci
17e5b75505Sopenharmony_ci
18e5b75505Sopenharmony_cichar *wpas_ctrl_path = "/var/run/wpa_supplicant/";
19e5b75505Sopenharmony_cistatic int default_timeout = 60;
20e5b75505Sopenharmony_ci
21e5b75505Sopenharmony_ci
22e5b75505Sopenharmony_cistatic struct wpa_ctrl * wpa_open_ctrl(const char *ifname)
23e5b75505Sopenharmony_ci{
24e5b75505Sopenharmony_ci	char buf[128];
25e5b75505Sopenharmony_ci	struct wpa_ctrl *ctrl;
26e5b75505Sopenharmony_ci
27e5b75505Sopenharmony_ci	os_snprintf(buf, sizeof(buf), "%s%s", wpas_ctrl_path, ifname);
28e5b75505Sopenharmony_ci	ctrl = wpa_ctrl_open(buf);
29e5b75505Sopenharmony_ci	if (ctrl == NULL)
30e5b75505Sopenharmony_ci		printf("wpa_command: wpa_ctrl_open(%s) failed\n", buf);
31e5b75505Sopenharmony_ci	return ctrl;
32e5b75505Sopenharmony_ci}
33e5b75505Sopenharmony_ci
34e5b75505Sopenharmony_ci
35e5b75505Sopenharmony_ciint wpa_command(const char *ifname, const char *cmd)
36e5b75505Sopenharmony_ci{
37e5b75505Sopenharmony_ci	struct wpa_ctrl *ctrl;
38e5b75505Sopenharmony_ci	char buf[128];
39e5b75505Sopenharmony_ci	size_t len;
40e5b75505Sopenharmony_ci
41e5b75505Sopenharmony_ci	printf("wpa_command(ifname='%s', cmd='%s')\n", ifname, cmd);
42e5b75505Sopenharmony_ci	ctrl = wpa_open_ctrl(ifname);
43e5b75505Sopenharmony_ci	if (ctrl == NULL)
44e5b75505Sopenharmony_ci		return -1;
45e5b75505Sopenharmony_ci	len = sizeof(buf);
46e5b75505Sopenharmony_ci	if (wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL) < 0) {
47e5b75505Sopenharmony_ci		printf("wpa_command: wpa_ctrl_request failed\n");
48e5b75505Sopenharmony_ci		wpa_ctrl_close(ctrl);
49e5b75505Sopenharmony_ci		return -1;
50e5b75505Sopenharmony_ci	}
51e5b75505Sopenharmony_ci	wpa_ctrl_close(ctrl);
52e5b75505Sopenharmony_ci	buf[len] = '\0';
53e5b75505Sopenharmony_ci	if (strncmp(buf, "FAIL", 4) == 0) {
54e5b75505Sopenharmony_ci		printf("wpa_command: Command failed (FAIL received)\n");
55e5b75505Sopenharmony_ci		return -1;
56e5b75505Sopenharmony_ci	}
57e5b75505Sopenharmony_ci	return 0;
58e5b75505Sopenharmony_ci}
59e5b75505Sopenharmony_ci
60e5b75505Sopenharmony_ci
61e5b75505Sopenharmony_ciint wpa_command_resp(const char *ifname, const char *cmd,
62e5b75505Sopenharmony_ci		     char *resp, size_t resp_size)
63e5b75505Sopenharmony_ci{
64e5b75505Sopenharmony_ci	struct wpa_ctrl *ctrl;
65e5b75505Sopenharmony_ci	size_t len;
66e5b75505Sopenharmony_ci
67e5b75505Sopenharmony_ci	printf("wpa_command(ifname='%s', cmd='%s')\n", ifname, cmd);
68e5b75505Sopenharmony_ci	ctrl = wpa_open_ctrl(ifname);
69e5b75505Sopenharmony_ci	if (ctrl == NULL)
70e5b75505Sopenharmony_ci		return -1;
71e5b75505Sopenharmony_ci	len = resp_size;
72e5b75505Sopenharmony_ci	if (wpa_ctrl_request(ctrl, cmd, strlen(cmd), resp, &len, NULL) < 0) {
73e5b75505Sopenharmony_ci		printf("wpa_command: wpa_ctrl_request failed\n");
74e5b75505Sopenharmony_ci		wpa_ctrl_close(ctrl);
75e5b75505Sopenharmony_ci		return -1;
76e5b75505Sopenharmony_ci	}
77e5b75505Sopenharmony_ci	wpa_ctrl_close(ctrl);
78e5b75505Sopenharmony_ci	resp[len] = '\0';
79e5b75505Sopenharmony_ci	return 0;
80e5b75505Sopenharmony_ci}
81e5b75505Sopenharmony_ci
82e5b75505Sopenharmony_ci
83e5b75505Sopenharmony_cistruct wpa_ctrl * open_wpa_mon(const char *ifname)
84e5b75505Sopenharmony_ci{
85e5b75505Sopenharmony_ci	struct wpa_ctrl *ctrl;
86e5b75505Sopenharmony_ci
87e5b75505Sopenharmony_ci	ctrl = wpa_open_ctrl(ifname);
88e5b75505Sopenharmony_ci	if (ctrl == NULL)
89e5b75505Sopenharmony_ci		return NULL;
90e5b75505Sopenharmony_ci	if (wpa_ctrl_attach(ctrl) < 0) {
91e5b75505Sopenharmony_ci		wpa_ctrl_close(ctrl);
92e5b75505Sopenharmony_ci		return NULL;
93e5b75505Sopenharmony_ci	}
94e5b75505Sopenharmony_ci
95e5b75505Sopenharmony_ci	return ctrl;
96e5b75505Sopenharmony_ci}
97e5b75505Sopenharmony_ci
98e5b75505Sopenharmony_ci
99e5b75505Sopenharmony_ciint get_wpa_cli_event2(struct wpa_ctrl *mon,
100e5b75505Sopenharmony_ci		       const char *event, const char *event2,
101e5b75505Sopenharmony_ci		       char *buf, size_t buf_size)
102e5b75505Sopenharmony_ci{
103e5b75505Sopenharmony_ci	int fd, ret;
104e5b75505Sopenharmony_ci	fd_set rfd;
105e5b75505Sopenharmony_ci	char *pos;
106e5b75505Sopenharmony_ci	struct timeval tv;
107e5b75505Sopenharmony_ci	time_t start, now;
108e5b75505Sopenharmony_ci
109e5b75505Sopenharmony_ci	printf("Waiting for wpa_cli event %s\n", event);
110e5b75505Sopenharmony_ci	fd = wpa_ctrl_get_fd(mon);
111e5b75505Sopenharmony_ci	if (fd < 0)
112e5b75505Sopenharmony_ci		return -1;
113e5b75505Sopenharmony_ci
114e5b75505Sopenharmony_ci	time(&start);
115e5b75505Sopenharmony_ci	while (1) {
116e5b75505Sopenharmony_ci		size_t len;
117e5b75505Sopenharmony_ci
118e5b75505Sopenharmony_ci		FD_ZERO(&rfd);
119e5b75505Sopenharmony_ci		FD_SET(fd, &rfd);
120e5b75505Sopenharmony_ci		tv.tv_sec = default_timeout;
121e5b75505Sopenharmony_ci		tv.tv_usec = 0;
122e5b75505Sopenharmony_ci		ret = select(fd + 1, &rfd, NULL, NULL, &tv);
123e5b75505Sopenharmony_ci		if (ret == 0) {
124e5b75505Sopenharmony_ci			printf("Timeout on waiting for event %s\n", event);
125e5b75505Sopenharmony_ci			return -1;
126e5b75505Sopenharmony_ci		}
127e5b75505Sopenharmony_ci		if (ret < 0) {
128e5b75505Sopenharmony_ci			printf("select: %s\n", strerror(errno));
129e5b75505Sopenharmony_ci			return -1;
130e5b75505Sopenharmony_ci		}
131e5b75505Sopenharmony_ci		len = buf_size;
132e5b75505Sopenharmony_ci		if (wpa_ctrl_recv(mon, buf, &len) < 0) {
133e5b75505Sopenharmony_ci			printf("Failure while waiting for event %s\n", event);
134e5b75505Sopenharmony_ci			return -1;
135e5b75505Sopenharmony_ci		}
136e5b75505Sopenharmony_ci		if (len == buf_size)
137e5b75505Sopenharmony_ci			len--;
138e5b75505Sopenharmony_ci		buf[len] = '\0';
139e5b75505Sopenharmony_ci
140e5b75505Sopenharmony_ci		pos = strchr(buf, '>');
141e5b75505Sopenharmony_ci		if (pos &&
142e5b75505Sopenharmony_ci		    (strncmp(pos + 1, event, strlen(event)) == 0 ||
143e5b75505Sopenharmony_ci		     (event2 &&
144e5b75505Sopenharmony_ci		      strncmp(pos + 1, event2, strlen(event2)) == 0)))
145e5b75505Sopenharmony_ci			return 0; /* Event found */
146e5b75505Sopenharmony_ci
147e5b75505Sopenharmony_ci		time(&now);
148e5b75505Sopenharmony_ci		if ((int) (now - start) > default_timeout) {
149e5b75505Sopenharmony_ci			printf("Timeout on waiting for event %s\n", event);
150e5b75505Sopenharmony_ci			return -1;
151e5b75505Sopenharmony_ci		}
152e5b75505Sopenharmony_ci	}
153e5b75505Sopenharmony_ci}
154e5b75505Sopenharmony_ci
155e5b75505Sopenharmony_ci
156e5b75505Sopenharmony_ciint get_wpa_cli_event(struct wpa_ctrl *mon,
157e5b75505Sopenharmony_ci		      const char *event, char *buf, size_t buf_size)
158e5b75505Sopenharmony_ci{
159e5b75505Sopenharmony_ci	return get_wpa_cli_event2(mon, event, NULL, buf, buf_size);
160e5b75505Sopenharmony_ci}
161e5b75505Sopenharmony_ci
162e5b75505Sopenharmony_ci
163e5b75505Sopenharmony_ciint get_wpa_status(const char *ifname, const char *field, char *obuf,
164e5b75505Sopenharmony_ci		   size_t obuf_size)
165e5b75505Sopenharmony_ci{
166e5b75505Sopenharmony_ci	struct wpa_ctrl *ctrl;
167e5b75505Sopenharmony_ci	char buf[4096];
168e5b75505Sopenharmony_ci	char *pos, *end;
169e5b75505Sopenharmony_ci	size_t len, flen;
170e5b75505Sopenharmony_ci
171e5b75505Sopenharmony_ci	ctrl = wpa_open_ctrl(ifname);
172e5b75505Sopenharmony_ci	if (ctrl == NULL)
173e5b75505Sopenharmony_ci		return -1;
174e5b75505Sopenharmony_ci	len = sizeof(buf);
175e5b75505Sopenharmony_ci	if (wpa_ctrl_request(ctrl, "STATUS-NO_EVENTS", 16, buf, &len,
176e5b75505Sopenharmony_ci			     NULL) < 0) {
177e5b75505Sopenharmony_ci		wpa_ctrl_close(ctrl);
178e5b75505Sopenharmony_ci		return -1;
179e5b75505Sopenharmony_ci	}
180e5b75505Sopenharmony_ci	wpa_ctrl_close(ctrl);
181e5b75505Sopenharmony_ci	buf[len] = '\0';
182e5b75505Sopenharmony_ci
183e5b75505Sopenharmony_ci	flen = strlen(field);
184e5b75505Sopenharmony_ci	pos = buf;
185e5b75505Sopenharmony_ci	while (pos + flen < buf + len) {
186e5b75505Sopenharmony_ci		if (pos > buf) {
187e5b75505Sopenharmony_ci			if (*pos != '\n') {
188e5b75505Sopenharmony_ci				pos++;
189e5b75505Sopenharmony_ci				continue;
190e5b75505Sopenharmony_ci			}
191e5b75505Sopenharmony_ci			pos++;
192e5b75505Sopenharmony_ci		}
193e5b75505Sopenharmony_ci		if (strncmp(pos, field, flen) != 0 || pos[flen] != '=') {
194e5b75505Sopenharmony_ci			pos++;
195e5b75505Sopenharmony_ci			continue;
196e5b75505Sopenharmony_ci		}
197e5b75505Sopenharmony_ci		pos += flen + 1;
198e5b75505Sopenharmony_ci		end = strchr(pos, '\n');
199e5b75505Sopenharmony_ci		if (end == NULL)
200e5b75505Sopenharmony_ci			return -1;
201e5b75505Sopenharmony_ci		*end++ = '\0';
202e5b75505Sopenharmony_ci		if (end - pos > (int) obuf_size)
203e5b75505Sopenharmony_ci			return -1;
204e5b75505Sopenharmony_ci		memcpy(obuf, pos, end - pos);
205e5b75505Sopenharmony_ci		return 0;
206e5b75505Sopenharmony_ci	}
207e5b75505Sopenharmony_ci
208e5b75505Sopenharmony_ci	return -1;
209e5b75505Sopenharmony_ci}
210e5b75505Sopenharmony_ci
211e5b75505Sopenharmony_ci
212e5b75505Sopenharmony_ciint wait_ip_addr(const char *ifname, int timeout)
213e5b75505Sopenharmony_ci{
214e5b75505Sopenharmony_ci	char ip[30];
215e5b75505Sopenharmony_ci	int count = timeout;
216e5b75505Sopenharmony_ci	struct wpa_ctrl *ctrl;
217e5b75505Sopenharmony_ci
218e5b75505Sopenharmony_ci	while (count > 0) {
219e5b75505Sopenharmony_ci		printf("%s: ifname='%s' - %d seconds remaining\n",
220e5b75505Sopenharmony_ci		       __func__, ifname, count);
221e5b75505Sopenharmony_ci		count--;
222e5b75505Sopenharmony_ci		if (get_wpa_status(ifname, "ip_address", ip, sizeof(ip)) == 0
223e5b75505Sopenharmony_ci		    && strlen(ip) > 0) {
224e5b75505Sopenharmony_ci			printf("IP address found: '%s'\n", ip);
225e5b75505Sopenharmony_ci			if (strncmp(ip, "169.254.", 8) != 0)
226e5b75505Sopenharmony_ci				return 0;
227e5b75505Sopenharmony_ci		}
228e5b75505Sopenharmony_ci		ctrl = wpa_open_ctrl(ifname);
229e5b75505Sopenharmony_ci		if (ctrl == NULL)
230e5b75505Sopenharmony_ci			return -1;
231e5b75505Sopenharmony_ci		wpa_ctrl_close(ctrl);
232e5b75505Sopenharmony_ci		sleep(1);
233e5b75505Sopenharmony_ci	}
234e5b75505Sopenharmony_ci	printf("%s: Could not get IP address for ifname='%s'", __func__,
235e5b75505Sopenharmony_ci	       ifname);
236e5b75505Sopenharmony_ci	return -1;
237e5b75505Sopenharmony_ci}
238e5b75505Sopenharmony_ci
239e5b75505Sopenharmony_ci
240e5b75505Sopenharmony_ciint add_network(const char *ifname)
241e5b75505Sopenharmony_ci{
242e5b75505Sopenharmony_ci	char res[30];
243e5b75505Sopenharmony_ci
244e5b75505Sopenharmony_ci	if (wpa_command_resp(ifname, "ADD_NETWORK", res, sizeof(res)) < 0)
245e5b75505Sopenharmony_ci		return -1;
246e5b75505Sopenharmony_ci	return atoi(res);
247e5b75505Sopenharmony_ci}
248e5b75505Sopenharmony_ci
249e5b75505Sopenharmony_ci
250e5b75505Sopenharmony_ciint set_network(const char *ifname, int id, const char *field,
251e5b75505Sopenharmony_ci		const char *value)
252e5b75505Sopenharmony_ci{
253e5b75505Sopenharmony_ci	char buf[200];
254e5b75505Sopenharmony_ci	snprintf(buf, sizeof(buf), "SET_NETWORK %d %s %s", id, field, value);
255e5b75505Sopenharmony_ci	return wpa_command(ifname, buf);
256e5b75505Sopenharmony_ci}
257e5b75505Sopenharmony_ci
258e5b75505Sopenharmony_ci
259e5b75505Sopenharmony_ciint set_network_quoted(const char *ifname, int id, const char *field,
260e5b75505Sopenharmony_ci		       const char *value)
261e5b75505Sopenharmony_ci{
262e5b75505Sopenharmony_ci	char buf[200];
263e5b75505Sopenharmony_ci	snprintf(buf, sizeof(buf), "SET_NETWORK %d %s \"%s\"",
264e5b75505Sopenharmony_ci		 id, field, value);
265e5b75505Sopenharmony_ci	return wpa_command(ifname, buf);
266e5b75505Sopenharmony_ci}
267e5b75505Sopenharmony_ci
268e5b75505Sopenharmony_ci
269e5b75505Sopenharmony_ciint add_cred(const char *ifname)
270e5b75505Sopenharmony_ci{
271e5b75505Sopenharmony_ci	char res[30];
272e5b75505Sopenharmony_ci
273e5b75505Sopenharmony_ci	if (wpa_command_resp(ifname, "ADD_CRED", res, sizeof(res)) < 0)
274e5b75505Sopenharmony_ci		return -1;
275e5b75505Sopenharmony_ci	return atoi(res);
276e5b75505Sopenharmony_ci}
277e5b75505Sopenharmony_ci
278e5b75505Sopenharmony_ci
279e5b75505Sopenharmony_ciint set_cred(const char *ifname, int id, const char *field, const char *value)
280e5b75505Sopenharmony_ci{
281e5b75505Sopenharmony_ci	char buf[200];
282e5b75505Sopenharmony_ci	snprintf(buf, sizeof(buf), "SET_CRED %d %s %s", id, field, value);
283e5b75505Sopenharmony_ci	return wpa_command(ifname, buf);
284e5b75505Sopenharmony_ci}
285e5b75505Sopenharmony_ci
286e5b75505Sopenharmony_ci
287e5b75505Sopenharmony_ciint set_cred_quoted(const char *ifname, int id, const char *field,
288e5b75505Sopenharmony_ci		    const char *value)
289e5b75505Sopenharmony_ci{
290e5b75505Sopenharmony_ci	char buf[200];
291e5b75505Sopenharmony_ci	snprintf(buf, sizeof(buf), "SET_CRED %d %s \"%s\"",
292e5b75505Sopenharmony_ci		 id, field, value);
293e5b75505Sopenharmony_ci	return wpa_command(ifname, buf);
294e5b75505Sopenharmony_ci}
295