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