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