1189251Ssam/*
2189251Ssam * WPA Supplicant / UDP socket -based control interface
3189251Ssam * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12189251Ssam#include "eloop.h"
13189251Ssam#include "config.h"
14189251Ssam#include "eapol_supp/eapol_supp_sm.h"
15189251Ssam#include "wpa_supplicant_i.h"
16189251Ssam#include "ctrl_iface.h"
17214734Srpaulo#include "common/wpa_ctrl.h"
18189251Ssam
19189251Ssam
20189251Ssam#define COOKIE_LEN 8
21189251Ssam
22189251Ssam/* Per-interface ctrl_iface */
23189251Ssam
24189251Ssam/**
25189251Ssam * struct wpa_ctrl_dst - Internal data structure of control interface monitors
26189251Ssam *
27189251Ssam * This structure is used to store information about registered control
28189251Ssam * interface monitors into struct wpa_supplicant. This data is private to
29189251Ssam * ctrl_iface_udp.c and should not be touched directly from other files.
30189251Ssam */
31189251Ssamstruct wpa_ctrl_dst {
32189251Ssam	struct wpa_ctrl_dst *next;
33189251Ssam	struct sockaddr_in addr;
34189251Ssam	socklen_t addrlen;
35189251Ssam	int debug_level;
36189251Ssam	int errors;
37189251Ssam};
38189251Ssam
39189251Ssam
40189251Ssamstruct ctrl_iface_priv {
41189251Ssam	struct wpa_supplicant *wpa_s;
42189251Ssam	int sock;
43189251Ssam	struct wpa_ctrl_dst *ctrl_dst;
44189251Ssam	u8 cookie[COOKIE_LEN];
45189251Ssam};
46189251Ssam
47189251Ssam
48189251Ssamstatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
49189251Ssam					   int level, const char *buf,
50189251Ssam					   size_t len);
51189251Ssam
52189251Ssam
53189251Ssamstatic int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
54189251Ssam					    struct sockaddr_in *from,
55189251Ssam					    socklen_t fromlen)
56189251Ssam{
57189251Ssam	struct wpa_ctrl_dst *dst;
58189251Ssam
59189251Ssam	dst = os_zalloc(sizeof(*dst));
60189251Ssam	if (dst == NULL)
61189251Ssam		return -1;
62189251Ssam	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in));
63189251Ssam	dst->addrlen = fromlen;
64189251Ssam	dst->debug_level = MSG_INFO;
65189251Ssam	dst->next = priv->ctrl_dst;
66189251Ssam	priv->ctrl_dst = dst;
67189251Ssam	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
68189251Ssam		   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
69189251Ssam	return 0;
70189251Ssam}
71189251Ssam
72189251Ssam
73189251Ssamstatic int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
74189251Ssam					    struct sockaddr_in *from,
75189251Ssam					    socklen_t fromlen)
76189251Ssam{
77189251Ssam	struct wpa_ctrl_dst *dst, *prev = NULL;
78189251Ssam
79189251Ssam	dst = priv->ctrl_dst;
80189251Ssam	while (dst) {
81189251Ssam		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
82189251Ssam		    from->sin_port == dst->addr.sin_port) {
83189251Ssam			if (prev == NULL)
84189251Ssam				priv->ctrl_dst = dst->next;
85189251Ssam			else
86189251Ssam				prev->next = dst->next;
87189251Ssam			os_free(dst);
88189251Ssam			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
89189251Ssam				   "%s:%d", inet_ntoa(from->sin_addr),
90189251Ssam				   ntohs(from->sin_port));
91189251Ssam			return 0;
92189251Ssam		}
93189251Ssam		prev = dst;
94189251Ssam		dst = dst->next;
95189251Ssam	}
96189251Ssam	return -1;
97189251Ssam}
98189251Ssam
99189251Ssam
100189251Ssamstatic int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
101189251Ssam					   struct sockaddr_in *from,
102189251Ssam					   socklen_t fromlen,
103189251Ssam					   char *level)
104189251Ssam{
105189251Ssam	struct wpa_ctrl_dst *dst;
106189251Ssam
107189251Ssam	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
108189251Ssam
109189251Ssam	dst = priv->ctrl_dst;
110189251Ssam	while (dst) {
111189251Ssam		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
112189251Ssam		    from->sin_port == dst->addr.sin_port) {
113189251Ssam			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
114189251Ssam				   "level %s:%d", inet_ntoa(from->sin_addr),
115189251Ssam				   ntohs(from->sin_port));
116189251Ssam			dst->debug_level = atoi(level);
117189251Ssam			return 0;
118189251Ssam		}
119189251Ssam		dst = dst->next;
120189251Ssam	}
121189251Ssam
122189251Ssam	return -1;
123189251Ssam}
124189251Ssam
125189251Ssam
126189251Ssamstatic char *
127189251Ssamwpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
128189251Ssam				     size_t *reply_len)
129189251Ssam{
130189251Ssam	char *reply;
131189251Ssam	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
132189251Ssam	if (reply == NULL) {
133189251Ssam		*reply_len = 1;
134189251Ssam		return NULL;
135189251Ssam	}
136189251Ssam
137189251Ssam	os_memcpy(reply, "COOKIE=", 7);
138189251Ssam	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
139189251Ssam			 priv->cookie, COOKIE_LEN);
140189251Ssam
141189251Ssam	*reply_len = 7 + 2 * COOKIE_LEN;
142189251Ssam	return reply;
143189251Ssam}
144189251Ssam
145189251Ssam
146189251Ssamstatic void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
147189251Ssam					      void *sock_ctx)
148189251Ssam{
149189251Ssam	struct wpa_supplicant *wpa_s = eloop_ctx;
150189251Ssam	struct ctrl_iface_priv *priv = sock_ctx;
151189251Ssam	char buf[256], *pos;
152189251Ssam	int res;
153189251Ssam	struct sockaddr_in from;
154189251Ssam	socklen_t fromlen = sizeof(from);
155189251Ssam	char *reply = NULL;
156189251Ssam	size_t reply_len = 0;
157189251Ssam	int new_attached = 0;
158189251Ssam	u8 cookie[COOKIE_LEN];
159189251Ssam
160189251Ssam	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
161189251Ssam		       (struct sockaddr *) &from, &fromlen);
162189251Ssam	if (res < 0) {
163189251Ssam		perror("recvfrom(ctrl_iface)");
164189251Ssam		return;
165189251Ssam	}
166252726Srpaulo
167252726Srpaulo#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
168189251Ssam	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
169189251Ssam		/*
170189251Ssam		 * The OS networking stack is expected to drop this kind of
171189251Ssam		 * frames since the socket is bound to only localhost address.
172189251Ssam		 * Just in case, drop the frame if it is coming from any other
173189251Ssam		 * address.
174189251Ssam		 */
175189251Ssam		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
176189251Ssam			   "source %s", inet_ntoa(from.sin_addr));
177189251Ssam		return;
178189251Ssam	}
179252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
180252726Srpaulo
181189251Ssam	buf[res] = '\0';
182189251Ssam
183189251Ssam	if (os_strcmp(buf, "GET_COOKIE") == 0) {
184189251Ssam		reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
185189251Ssam		goto done;
186189251Ssam	}
187189251Ssam
188189251Ssam	/*
189189251Ssam	 * Require that the client includes a prefix with the 'cookie' value
190189251Ssam	 * fetched with GET_COOKIE command. This is used to verify that the
191189251Ssam	 * client has access to a bidirectional link over UDP in order to
192189251Ssam	 * avoid attacks using forged localhost IP address even if the OS does
193189251Ssam	 * not block such frames from remote destinations.
194189251Ssam	 */
195189251Ssam	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
196189251Ssam		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
197189251Ssam			   "drop request");
198189251Ssam		return;
199189251Ssam	}
200189251Ssam
201189251Ssam	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
202189251Ssam		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
203189251Ssam			   "request - drop request");
204189251Ssam		return;
205189251Ssam	}
206189251Ssam
207189251Ssam	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
208189251Ssam		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
209189251Ssam			   "drop request");
210189251Ssam		return;
211189251Ssam	}
212189251Ssam
213189251Ssam	pos = buf + 7 + 2 * COOKIE_LEN;
214189251Ssam	while (*pos == ' ')
215189251Ssam		pos++;
216189251Ssam
217189251Ssam	if (os_strcmp(pos, "ATTACH") == 0) {
218189251Ssam		if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
219189251Ssam			reply_len = 1;
220189251Ssam		else {
221189251Ssam			new_attached = 1;
222189251Ssam			reply_len = 2;
223189251Ssam		}
224189251Ssam	} else if (os_strcmp(pos, "DETACH") == 0) {
225189251Ssam		if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
226189251Ssam			reply_len = 1;
227189251Ssam		else
228189251Ssam			reply_len = 2;
229189251Ssam	} else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
230189251Ssam		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
231189251Ssam						    pos + 6))
232189251Ssam			reply_len = 1;
233189251Ssam		else
234189251Ssam			reply_len = 2;
235189251Ssam	} else {
236189251Ssam		reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
237189251Ssam							  &reply_len);
238189251Ssam	}
239189251Ssam
240189251Ssam done:
241189251Ssam	if (reply) {
242189251Ssam		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
243189251Ssam		       fromlen);
244189251Ssam		os_free(reply);
245189251Ssam	} else if (reply_len == 1) {
246189251Ssam		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
247189251Ssam		       fromlen);
248189251Ssam	} else if (reply_len == 2) {
249189251Ssam		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
250189251Ssam		       fromlen);
251189251Ssam	}
252189251Ssam
253189251Ssam	if (new_attached)
254189251Ssam		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
255189251Ssam}
256189251Ssam
257189251Ssam
258189251Ssamstatic void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
259189251Ssam					     const char *txt, size_t len)
260189251Ssam{
261189251Ssam	struct wpa_supplicant *wpa_s = ctx;
262189251Ssam	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
263189251Ssam		return;
264189251Ssam	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
265189251Ssam}
266189251Ssam
267189251Ssam
268189251Ssamstruct ctrl_iface_priv *
269189251Ssamwpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
270189251Ssam{
271189251Ssam	struct ctrl_iface_priv *priv;
272189251Ssam	struct sockaddr_in addr;
273252726Srpaulo	int port = WPA_CTRL_IFACE_PORT;
274189251Ssam
275189251Ssam	priv = os_zalloc(sizeof(*priv));
276189251Ssam	if (priv == NULL)
277189251Ssam		return NULL;
278189251Ssam	priv->wpa_s = wpa_s;
279189251Ssam	priv->sock = -1;
280189251Ssam	os_get_random(priv->cookie, COOKIE_LEN);
281189251Ssam
282189251Ssam	if (wpa_s->conf->ctrl_interface == NULL)
283189251Ssam		return priv;
284189251Ssam
285189251Ssam	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
286189251Ssam	if (priv->sock < 0) {
287189251Ssam		perror("socket(PF_INET)");
288189251Ssam		goto fail;
289189251Ssam	}
290189251Ssam
291189251Ssam	os_memset(&addr, 0, sizeof(addr));
292189251Ssam	addr.sin_family = AF_INET;
293252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
294252726Srpaulo	addr.sin_addr.s_addr = INADDR_ANY;
295252726Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
296189251Ssam	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
297252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
298252726Srpaulotry_again:
299252726Srpaulo	addr.sin_port = htons(port);
300189251Ssam	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
301252726Srpaulo		port--;
302252726Srpaulo		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
303252726Srpaulo			goto try_again;
304189251Ssam		perror("bind(AF_INET)");
305189251Ssam		goto fail;
306189251Ssam	}
307189251Ssam
308252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
309252726Srpaulo	wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
310252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
311252726Srpaulo
312189251Ssam	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
313189251Ssam				 wpa_s, priv);
314189251Ssam	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
315189251Ssam
316189251Ssam	return priv;
317189251Ssam
318189251Ssamfail:
319189251Ssam	if (priv->sock >= 0)
320189251Ssam		close(priv->sock);
321189251Ssam	os_free(priv);
322189251Ssam	return NULL;
323189251Ssam}
324189251Ssam
325189251Ssam
326189251Ssamvoid wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
327189251Ssam{
328189251Ssam	struct wpa_ctrl_dst *dst, *prev;
329189251Ssam
330189251Ssam	if (priv->sock > -1) {
331189251Ssam		eloop_unregister_read_sock(priv->sock);
332189251Ssam		if (priv->ctrl_dst) {
333189251Ssam			/*
334189251Ssam			 * Wait a second before closing the control socket if
335189251Ssam			 * there are any attached monitors in order to allow
336189251Ssam			 * them to receive any pending messages.
337189251Ssam			 */
338189251Ssam			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
339189251Ssam				   "monitors to receive messages");
340189251Ssam			os_sleep(1, 0);
341189251Ssam		}
342189251Ssam		close(priv->sock);
343189251Ssam		priv->sock = -1;
344189251Ssam	}
345189251Ssam
346189251Ssam	dst = priv->ctrl_dst;
347189251Ssam	while (dst) {
348189251Ssam		prev = dst;
349189251Ssam		dst = dst->next;
350189251Ssam		os_free(prev);
351189251Ssam	}
352189251Ssam	os_free(priv);
353189251Ssam}
354189251Ssam
355189251Ssam
356189251Ssamstatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
357189251Ssam					   int level, const char *buf,
358189251Ssam					   size_t len)
359189251Ssam{
360189251Ssam	struct wpa_ctrl_dst *dst, *next;
361189251Ssam	char levelstr[10];
362189251Ssam	int idx;
363189251Ssam	char *sbuf;
364189251Ssam	int llen;
365189251Ssam
366189251Ssam	dst = priv->ctrl_dst;
367189251Ssam	if (priv->sock < 0 || dst == NULL)
368189251Ssam		return;
369189251Ssam
370189251Ssam	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
371189251Ssam
372189251Ssam	llen = os_strlen(levelstr);
373189251Ssam	sbuf = os_malloc(llen + len);
374189251Ssam	if (sbuf == NULL)
375189251Ssam		return;
376189251Ssam
377189251Ssam	os_memcpy(sbuf, levelstr, llen);
378189251Ssam	os_memcpy(sbuf + llen, buf, len);
379189251Ssam
380189251Ssam	idx = 0;
381189251Ssam	while (dst) {
382189251Ssam		next = dst->next;
383189251Ssam		if (level >= dst->debug_level) {
384189251Ssam			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
385189251Ssam				   inet_ntoa(dst->addr.sin_addr),
386189251Ssam				   ntohs(dst->addr.sin_port));
387189251Ssam			if (sendto(priv->sock, sbuf, llen + len, 0,
388189251Ssam				   (struct sockaddr *) &dst->addr,
389189251Ssam				   sizeof(dst->addr)) < 0) {
390189251Ssam				perror("sendto(CTRL_IFACE monitor)");
391189251Ssam				dst->errors++;
392189251Ssam				if (dst->errors > 10) {
393189251Ssam					wpa_supplicant_ctrl_iface_detach(
394189251Ssam						priv, &dst->addr,
395189251Ssam						dst->addrlen);
396189251Ssam				}
397189251Ssam			} else
398189251Ssam				dst->errors = 0;
399189251Ssam		}
400189251Ssam		idx++;
401189251Ssam		dst = next;
402189251Ssam	}
403189251Ssam	os_free(sbuf);
404189251Ssam}
405189251Ssam
406189251Ssam
407189251Ssamvoid wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
408189251Ssam{
409189251Ssam	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
410189251Ssam		   priv->wpa_s->ifname);
411189251Ssam	eloop_wait_for_read_sock(priv->sock);
412189251Ssam}
413189251Ssam
414189251Ssam
415189251Ssam/* Global ctrl_iface */
416189251Ssam
417189251Ssamstruct ctrl_iface_global_priv {
418189251Ssam	int sock;
419189251Ssam	u8 cookie[COOKIE_LEN];
420189251Ssam};
421189251Ssam
422189251Ssam
423189251Ssamstatic char *
424189251Ssamwpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
425189251Ssam				 size_t *reply_len)
426189251Ssam{
427189251Ssam	char *reply;
428189251Ssam	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
429189251Ssam	if (reply == NULL) {
430189251Ssam		*reply_len = 1;
431189251Ssam		return NULL;
432189251Ssam	}
433189251Ssam
434189251Ssam	os_memcpy(reply, "COOKIE=", 7);
435189251Ssam	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
436189251Ssam			 priv->cookie, COOKIE_LEN);
437189251Ssam
438189251Ssam	*reply_len = 7 + 2 * COOKIE_LEN;
439189251Ssam	return reply;
440189251Ssam}
441189251Ssam
442189251Ssam
443189251Ssamstatic void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
444189251Ssam						     void *sock_ctx)
445189251Ssam{
446189251Ssam	struct wpa_global *global = eloop_ctx;
447189251Ssam	struct ctrl_iface_global_priv *priv = sock_ctx;
448189251Ssam	char buf[256], *pos;
449189251Ssam	int res;
450189251Ssam	struct sockaddr_in from;
451189251Ssam	socklen_t fromlen = sizeof(from);
452189251Ssam	char *reply;
453189251Ssam	size_t reply_len;
454189251Ssam	u8 cookie[COOKIE_LEN];
455189251Ssam
456189251Ssam	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
457189251Ssam		       (struct sockaddr *) &from, &fromlen);
458189251Ssam	if (res < 0) {
459189251Ssam		perror("recvfrom(ctrl_iface)");
460189251Ssam		return;
461189251Ssam	}
462252726Srpaulo
463252726Srpaulo#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
464189251Ssam	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
465189251Ssam		/*
466189251Ssam		 * The OS networking stack is expected to drop this kind of
467189251Ssam		 * frames since the socket is bound to only localhost address.
468189251Ssam		 * Just in case, drop the frame if it is coming from any other
469189251Ssam		 * address.
470189251Ssam		 */
471189251Ssam		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
472189251Ssam			   "source %s", inet_ntoa(from.sin_addr));
473189251Ssam		return;
474189251Ssam	}
475252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
476252726Srpaulo
477189251Ssam	buf[res] = '\0';
478189251Ssam
479189251Ssam	if (os_strcmp(buf, "GET_COOKIE") == 0) {
480189251Ssam		reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
481189251Ssam		goto done;
482189251Ssam	}
483189251Ssam
484189251Ssam	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
485189251Ssam		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
486189251Ssam			   "drop request");
487189251Ssam		return;
488189251Ssam	}
489189251Ssam
490189251Ssam	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
491189251Ssam		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
492189251Ssam			   "request - drop request");
493189251Ssam		return;
494189251Ssam	}
495189251Ssam
496189251Ssam	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
497189251Ssam		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
498189251Ssam			   "drop request");
499189251Ssam		return;
500189251Ssam	}
501189251Ssam
502189251Ssam	pos = buf + 7 + 2 * COOKIE_LEN;
503189251Ssam	while (*pos == ' ')
504189251Ssam		pos++;
505189251Ssam
506189251Ssam	reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
507189251Ssam							 &reply_len);
508189251Ssam
509189251Ssam done:
510189251Ssam	if (reply) {
511189251Ssam		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
512189251Ssam		       fromlen);
513189251Ssam		os_free(reply);
514189251Ssam	} else if (reply_len) {
515189251Ssam		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
516189251Ssam		       fromlen);
517189251Ssam	}
518189251Ssam}
519189251Ssam
520189251Ssam
521189251Ssamstruct ctrl_iface_global_priv *
522189251Ssamwpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
523189251Ssam{
524189251Ssam	struct ctrl_iface_global_priv *priv;
525189251Ssam	struct sockaddr_in addr;
526252726Srpaulo	int port = WPA_GLOBAL_CTRL_IFACE_PORT;
527189251Ssam
528189251Ssam	priv = os_zalloc(sizeof(*priv));
529189251Ssam	if (priv == NULL)
530189251Ssam		return NULL;
531189251Ssam	priv->sock = -1;
532189251Ssam	os_get_random(priv->cookie, COOKIE_LEN);
533189251Ssam
534189251Ssam	if (global->params.ctrl_interface == NULL)
535189251Ssam		return priv;
536189251Ssam
537189251Ssam	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
538189251Ssam		   global->params.ctrl_interface);
539189251Ssam
540189251Ssam	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
541189251Ssam	if (priv->sock < 0) {
542189251Ssam		perror("socket(PF_INET)");
543189251Ssam		goto fail;
544189251Ssam	}
545189251Ssam
546189251Ssam	os_memset(&addr, 0, sizeof(addr));
547189251Ssam	addr.sin_family = AF_INET;
548252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
549252726Srpaulo	addr.sin_addr.s_addr = INADDR_ANY;
550252726Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
551189251Ssam	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
552252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
553252726Srpaulotry_again:
554252726Srpaulo	addr.sin_port = htons(port);
555189251Ssam	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
556252726Srpaulo		port++;
557252726Srpaulo		if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
558252726Srpaulo		    WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
559252726Srpaulo			goto try_again;
560189251Ssam		perror("bind(AF_INET)");
561189251Ssam		goto fail;
562189251Ssam	}
563189251Ssam
564252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
565252726Srpaulo	wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
566252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
567252726Srpaulo
568189251Ssam	eloop_register_read_sock(priv->sock,
569189251Ssam				 wpa_supplicant_global_ctrl_iface_receive,
570189251Ssam				 global, priv);
571189251Ssam
572189251Ssam	return priv;
573189251Ssam
574189251Ssamfail:
575189251Ssam	if (priv->sock >= 0)
576189251Ssam		close(priv->sock);
577189251Ssam	os_free(priv);
578189251Ssam	return NULL;
579189251Ssam}
580189251Ssam
581189251Ssam
582189251Ssamvoid
583189251Ssamwpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
584189251Ssam{
585189251Ssam	if (priv->sock >= 0) {
586189251Ssam		eloop_unregister_read_sock(priv->sock);
587189251Ssam		close(priv->sock);
588189251Ssam	}
589189251Ssam	os_free(priv);
590189251Ssam}
591