18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant / UDP socket -based control interface
3e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "config.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eapol_supp/eapol_supp_sm.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpa_supplicant_i.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ctrl_iface.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/wpa_ctrl.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define COOKIE_LEN 8
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Per-interface ctrl_iface */
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct wpa_ctrl_dst - Internal data structure of control interface monitors
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This structure is used to store information about registered control
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * interface monitors into struct wpa_supplicant. This data is private to
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ctrl_iface_udp.c and should not be touched directly from other files.
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_ctrl_dst {
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ctrl_dst *next;
33f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
34f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct sockaddr_in6 addr;
35f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in addr;
37f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	socklen_t addrlen;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int debug_level;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int errors;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct ctrl_iface_priv {
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sock;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ctrl_dst *ctrl_dst;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 cookie[COOKIE_LEN];
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidtstruct ctrl_iface_global_priv {
5231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	int sock;
5331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	struct wpa_ctrl_dst *ctrl_dst;
5431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	u8 cookie[COOKIE_LEN];
5531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt};
5631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidtstatic void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
5931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt					   const char *ifname, int sock,
6031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt					   struct wpa_ctrl_dst **head,
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   int level, const char *buf,
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   size_t len);
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidtstatic void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst)
6631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt{
6731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	struct wpa_ctrl_dst *prev;
6831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
6931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	while (dst) {
7031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		prev = dst;
7131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		dst = dst->next;
7231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		os_free(prev);
7331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	}
7431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt}
7531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
7631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
7731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidtstatic int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head,
78f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
79f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					    struct sockaddr_in6 *from,
80f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    struct sockaddr_in *from,
82f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    socklen_t fromlen)
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ctrl_dst *dst;
86f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
87f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	char addr[INET6_ADDRSTRLEN];
88f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_UDP_IPV6 */
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst = os_zalloc(sizeof(*dst));
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dst == NULL)
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
93f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	os_memcpy(&dst->addr, from, sizeof(*from));
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->addrlen = fromlen;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->debug_level = MSG_INFO;
9631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	dst->next = *head;
9731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	*head = dst;
98f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
99f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
100f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
101f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		   ntohs(from->sin6_port));
102f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
105f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidtstatic int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head,
111f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
112f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					    struct sockaddr_in6 *from,
113f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    struct sockaddr_in *from,
115f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    socklen_t fromlen)
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ctrl_dst *dst, *prev = NULL;
119f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
120f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	char addr[INET6_ADDRSTRLEN];
121f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	dst = *head;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (dst) {
125f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
126f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (from->sin6_port == dst->addr.sin6_port &&
127f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
128f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			       sizeof(from->sin6_addr))) {
129f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s:%d",
130f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   inet_ntop(AF_INET6, &from->sin6_addr, addr,
131f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					     sizeof(*from)),
132f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   ntohs(from->sin6_port));
133f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    from->sin_port == dst->addr.sin_port) {
136b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
137b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt				   "%s:%d", inet_ntoa(from->sin_addr),
138b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt				   ntohs(from->sin_port));
139f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev == NULL)
14131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				*head = dst->next;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = dst->next;
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(dst);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = dst;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dst = dst->next;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
155f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
156f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					   struct sockaddr_in6 *from,
157f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct sockaddr_in *from,
159f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   socklen_t fromlen,
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   char *level)
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ctrl_dst *dst;
164f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
165f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	char addr[INET6_ADDRSTRLEN];
166f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst = priv->ctrl_dst;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (dst) {
172f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#if CONFIG_CTRL_IFACE_UDP_IPV6
173f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		if (from->sin6_port == dst->addr.sin6_port &&
174f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		    !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
175f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			       sizeof(from->sin6_addr))) {
176f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level %s:%d",
177f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   inet_ntop(AF_INET6, &from->sin6_addr, addr,
178f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					     sizeof(*from)),
179f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   ntohs(from->sin6_port));
180f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    from->sin_port == dst->addr.sin_port) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "level %s:%d", inet_ntoa(from->sin_addr),
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   ntohs(from->sin_port));
186f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			dst->debug_level = atoi(level);
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dst = dst->next;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic char *
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     size_t *reply_len)
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *reply;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reply == NULL) {
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*reply_len = 1;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(reply, "COOKIE=", 7);
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 priv->cookie, COOKIE_LEN);
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*reply_len = 7 + 2 * COOKIE_LEN;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return reply;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      void *sock_ctx)
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = eloop_ctx;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ctrl_iface_priv *priv = sock_ctx;
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[256], *pos;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
224f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
225f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct sockaddr_in6 from;
226f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
227f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	char addr[INET6_ADDRSTRLEN];
228f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
229f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in from;
231f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	socklen_t fromlen = sizeof(from);
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *reply = NULL;
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t reply_len = 0;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int new_attached = 0;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 cookie[COOKIE_LEN];
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       (struct sockaddr *) &from, &fromlen);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
241fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
242fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   strerror(errno));
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
247f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
248f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
249f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (os_strcmp(addr, "::1")) {
250f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
251f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			   addr);
252f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	}
253f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The OS networking stack is expected to drop this kind of
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * frames since the socket is bound to only localhost address.
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Just in case, drop the frame if it is coming from any other
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * address.
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "source %s", inet_ntoa(from.sin_addr));
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
265f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[res] = '\0';
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strcmp(buf, "GET_COOKIE") == 0) {
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done;
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Require that the client includes a prefix with the 'cookie' value
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * fetched with GET_COOKIE command. This is used to verify that the
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * client has access to a bidirectional link over UDP in order to
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * avoid attacks using forged localhost IP address even if the OS does
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * not block such frames from remote destinations.
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "drop request");
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request - drop request");
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "drop request");
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf + 7 + 2 * COOKIE_LEN;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*pos == ' ')
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strcmp(pos, "ATTACH") == 0) {
30531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
30631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt						     &from, fromlen))
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reply_len = 1;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else {
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			new_attached = 1;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reply_len = 2;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (os_strcmp(pos, "DETACH") == 0) {
31331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
31431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt						     &from, fromlen))
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reply_len = 1;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reply_len = 2;
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						    pos + 6))
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reply_len = 1;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reply_len = 2;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							  &reply_len);
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt done:
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reply) {
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       fromlen);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(reply);
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (reply_len == 1) {
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       fromlen);
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (reply_len == 2) {
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       fromlen);
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (new_attached)
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3477a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidtstatic void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
3487a53dbb56693ee9f55c0cab1a8297436511e8613Dmitry Shmidt					     enum wpa_msg_type type,
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     const char *txt, size_t len)
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_supplicant *wpa_s = ctx;
35231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
35331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (!wpa_s)
35431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		return;
35531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
35631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
35731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
35831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
35931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		if (priv->ctrl_dst) {
36031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			wpa_supplicant_ctrl_iface_send(
36131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				wpa_s,
36231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				type != WPA_MSG_PER_INTERFACE ?
36331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				NULL : wpa_s->ifname,
36431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				priv->sock, &priv->ctrl_dst, level, txt, len);
36531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		}
36631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	}
36731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
36831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface)
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
37031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
37131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
37231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				       &wpa_s->ctrl_iface->ctrl_dst,
37331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				       level, txt, len);
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct ctrl_iface_priv *
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ctrl_iface_priv *priv;
381e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	char port_str[40];
38261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int port = WPA_CTRL_IFACE_PORT;
38331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	char *pos;
384f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
385f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct sockaddr_in6 addr;
386f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int domain = PF_INET6;
387f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
388f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	struct sockaddr_in addr;
389f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	int domain = PF_INET;
390f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	priv = os_zalloc(sizeof(*priv));
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv == NULL)
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	priv->wpa_s = wpa_s;
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	priv->sock = -1;
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_random(priv->cookie, COOKIE_LEN);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_s->conf->ctrl_interface == NULL)
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return priv;
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:");
40331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (pos) {
40431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		pos += 4;
40531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		port = atoi(pos);
40631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		if (port <= 0) {
40731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s",
40831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				   wpa_s->conf->ctrl_interface);
40931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			goto fail;
41031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		}
41131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	}
41231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
413f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	priv->sock = socket(domain, SOCK_DGRAM, 0);
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv->sock < 0) {
415fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&addr, 0, sizeof(addr));
420f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
421f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	addr.sin6_family = AF_INET6;
422f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
423f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	addr.sin6_addr = in6addr_any;
424f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
425f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	inet_pton(AF_INET6, "::1", &addr.sin6_addr);
426f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
427f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sin_family = AF_INET;
42961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
43061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	addr.sin_addr.s_addr = INADDR_ANY;
43161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
43361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
434f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
43561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidttry_again:
436f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
437f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	addr.sin6_port = htons(port);
438f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
43961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	addr.sin_port = htons(port);
440f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
44261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		port--;
443e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
44461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			goto try_again;
445fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
449e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	/* Update the ctrl_interface value to match the selected port */
450e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
451e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	os_free(wpa_s->conf->ctrl_interface);
452e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	wpa_s->conf->ctrl_interface = os_strdup(port_str);
453e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	if (!wpa_s->conf->ctrl_interface) {
454e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
455e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt		goto fail;
456e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	}
457e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt
45861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
45961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
46061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
46161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpa_s, priv);
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return priv;
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv->sock >= 0)
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(priv->sock);
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(priv);
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv->sock > -1) {
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(priv->sock);
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (priv->ctrl_dst) {
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
482b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			 * Wait before closing the control socket if
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * there are any attached monitors in order to allow
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * them to receive any pending messages.
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "monitors to receive messages");
488b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			os_sleep(0, 100000);
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(priv->sock);
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		priv->sock = -1;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	wpas_ctrl_iface_free_dst(priv->ctrl_dst);
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(priv);
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidtstatic void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
50031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt					   const char *ifname, int sock,
50131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt					   struct wpa_ctrl_dst **head,
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   int level, const char *buf,
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   size_t len)
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_ctrl_dst *dst, *next;
50631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	char levelstr[64];
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int idx;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *sbuf;
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int llen;
510f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
511f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	char addr[INET6_ADDRSTRLEN];
512f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	dst = *head;
51531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (sock < 0 || dst == NULL)
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (ifname)
51931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
52031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			    ifname, level);
52131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	else
52231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	llen = os_strlen(levelstr);
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sbuf = os_malloc(llen + len);
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sbuf == NULL)
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(sbuf, levelstr, llen);
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(sbuf + llen, buf, len);
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	idx = 0;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (dst) {
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		next = dst->next;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (level >= dst->debug_level) {
536f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
537f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
538f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   inet_ntop(AF_INET6, &dst->addr.sin6_addr,
539f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt					     addr, sizeof(dst->addr)),
540f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt				   ntohs(dst->addr.sin6_port));
541f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   inet_ntoa(dst->addr.sin_addr),
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   ntohs(dst->addr.sin_port));
545f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
54631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			if (sendto(sock, sbuf, llen + len, 0,
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (struct sockaddr *) &dst->addr,
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   sizeof(dst->addr)) < 0) {
549fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				wpa_printf(MSG_ERROR,
550fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt					   "sendto(CTRL_IFACE monitor): %s",
551fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt					   strerror(errno));
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				dst->errors++;
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (dst->errors > 10) {
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					wpa_supplicant_ctrl_iface_detach(
55531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt						head, &dst->addr,
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						dst->addrlen);
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				}
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			} else
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				dst->errors = 0;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		idx++;
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dst = next;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sbuf);
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   priv->wpa_s->ifname);
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_wait_for_read_sock(priv->sock);
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Global ctrl_iface */
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic char *
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 size_t *reply_len)
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *reply;
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reply == NULL) {
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*reply_len = 1;
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(reply, "COOKIE=", 7);
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 priv->cookie, COOKIE_LEN);
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*reply_len = 7 + 2 * COOKIE_LEN;
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return reply;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						     void *sock_ctx)
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_global *global = eloop_ctx;
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ctrl_iface_global_priv *priv = sock_ctx;
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[256], *pos;
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
605e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
606e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt	struct sockaddr_in6 from;
607e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in from;
609e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	socklen_t fromlen = sizeof(from);
61131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	char *reply = NULL;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t reply_len;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 cookie[COOKIE_LEN];
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       (struct sockaddr *) &from, &fromlen);
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
618fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
619fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   strerror(errno));
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
62361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
624e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The OS networking stack is expected to drop this kind of
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * frames since the socket is bound to only localhost address.
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Just in case, drop the frame if it is coming from any other
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * address.
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "source %s", inet_ntoa(from.sin_addr));
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
636e4663044d3a689fb5458247e9bc0f8b58cf72fcaDmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
63761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
63861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[res] = '\0';
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strcmp(buf, "GET_COOKIE") == 0) {
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done;
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "drop request");
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request - drop request");
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "drop request");
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf + 7 + 2 * COOKIE_LEN;
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*pos == ' ')
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
66831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (os_strcmp(pos, "ATTACH") == 0) {
66931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
67031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt						     &from, fromlen))
67131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			reply_len = 1;
67231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		else
67331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			reply_len = 2;
67431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	} else if (os_strcmp(pos, "DETACH") == 0) {
67531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
67631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt						     &from, fromlen))
67731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			reply_len = 1;
67831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		else
67931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			reply_len = 2;
68031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	} else {
68131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
68231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt								 &reply_len);
68331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	}
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt done:
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reply) {
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       fromlen);
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(reply);
69031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	} else if (reply_len == 1) {
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       fromlen);
69331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	} else if (reply_len == 2) {
69431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
69531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		       fromlen);
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct ctrl_iface_global_priv *
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ctrl_iface_global_priv *priv;
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in addr;
70531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	char *pos;
70661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int port = WPA_GLOBAL_CTRL_IFACE_PORT;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	priv = os_zalloc(sizeof(*priv));
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv == NULL)
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	priv->sock = -1;
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_random(priv->cookie, COOKIE_LEN);
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->params.ctrl_interface == NULL)
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return priv;
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   global->params.ctrl_interface);
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	pos = os_strstr(global->params.ctrl_interface, "udp:");
72131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	if (pos) {
72231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		pos += 4;
72331a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		port = atoi(pos);
72431a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		if (port <= 0) {
72531a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s",
72631a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt				   global->params.ctrl_interface);
72731a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt			goto fail;
72831a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		}
72931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	}
73031a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv->sock < 0) {
733fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&addr, 0, sizeof(addr));
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sin_family = AF_INET;
73961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
74061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	addr.sin_addr.s_addr = INADDR_ANY;
74161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
74361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
74461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidttry_again:
74561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	addr.sin_port = htons(port);
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
74761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		port++;
74861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
74931a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt		    WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
75061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			goto try_again;
751fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
75661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
75761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
75861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_read_sock(priv->sock,
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpa_supplicant_global_ctrl_iface_receive,
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 global, priv);
76231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return priv;
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv->sock >= 0)
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(priv->sock);
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(priv);
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (priv->sock >= 0) {
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(priv->sock);
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(priv->sock);
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
78131a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt
78231a29cc7ed87b62465c7e01f03484f4643d12309Dmitry Shmidt	wpas_ctrl_iface_free_dst(priv->ctrl_dst);
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(priv);
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
785