139beb93cSSam Leffler /* 239beb93cSSam Leffler * WPA Supplicant / UDP socket -based control interface 339beb93cSSam Leffler * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler #include "common.h" 1839beb93cSSam Leffler #include "eloop.h" 1939beb93cSSam Leffler #include "config.h" 2039beb93cSSam Leffler #include "eapol_supp/eapol_supp_sm.h" 2139beb93cSSam Leffler #include "wpa_supplicant_i.h" 2239beb93cSSam Leffler #include "ctrl_iface.h" 2339beb93cSSam Leffler #include "wpa_ctrl.h" 2439beb93cSSam Leffler 2539beb93cSSam Leffler 2639beb93cSSam Leffler #define COOKIE_LEN 8 2739beb93cSSam Leffler 2839beb93cSSam Leffler /* Per-interface ctrl_iface */ 2939beb93cSSam Leffler 3039beb93cSSam Leffler /** 3139beb93cSSam Leffler * struct wpa_ctrl_dst - Internal data structure of control interface monitors 3239beb93cSSam Leffler * 3339beb93cSSam Leffler * This structure is used to store information about registered control 3439beb93cSSam Leffler * interface monitors into struct wpa_supplicant. This data is private to 3539beb93cSSam Leffler * ctrl_iface_udp.c and should not be touched directly from other files. 3639beb93cSSam Leffler */ 3739beb93cSSam Leffler struct wpa_ctrl_dst { 3839beb93cSSam Leffler struct wpa_ctrl_dst *next; 3939beb93cSSam Leffler struct sockaddr_in addr; 4039beb93cSSam Leffler socklen_t addrlen; 4139beb93cSSam Leffler int debug_level; 4239beb93cSSam Leffler int errors; 4339beb93cSSam Leffler }; 4439beb93cSSam Leffler 4539beb93cSSam Leffler 4639beb93cSSam Leffler struct ctrl_iface_priv { 4739beb93cSSam Leffler struct wpa_supplicant *wpa_s; 4839beb93cSSam Leffler int sock; 4939beb93cSSam Leffler struct wpa_ctrl_dst *ctrl_dst; 5039beb93cSSam Leffler u8 cookie[COOKIE_LEN]; 5139beb93cSSam Leffler }; 5239beb93cSSam Leffler 5339beb93cSSam Leffler 5439beb93cSSam Leffler static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 5539beb93cSSam Leffler int level, const char *buf, 5639beb93cSSam Leffler size_t len); 5739beb93cSSam Leffler 5839beb93cSSam Leffler 5939beb93cSSam Leffler static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, 6039beb93cSSam Leffler struct sockaddr_in *from, 6139beb93cSSam Leffler socklen_t fromlen) 6239beb93cSSam Leffler { 6339beb93cSSam Leffler struct wpa_ctrl_dst *dst; 6439beb93cSSam Leffler 6539beb93cSSam Leffler dst = os_zalloc(sizeof(*dst)); 6639beb93cSSam Leffler if (dst == NULL) 6739beb93cSSam Leffler return -1; 6839beb93cSSam Leffler os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in)); 6939beb93cSSam Leffler dst->addrlen = fromlen; 7039beb93cSSam Leffler dst->debug_level = MSG_INFO; 7139beb93cSSam Leffler dst->next = priv->ctrl_dst; 7239beb93cSSam Leffler priv->ctrl_dst = dst; 7339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", 7439beb93cSSam Leffler inet_ntoa(from->sin_addr), ntohs(from->sin_port)); 7539beb93cSSam Leffler return 0; 7639beb93cSSam Leffler } 7739beb93cSSam Leffler 7839beb93cSSam Leffler 7939beb93cSSam Leffler static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, 8039beb93cSSam Leffler struct sockaddr_in *from, 8139beb93cSSam Leffler socklen_t fromlen) 8239beb93cSSam Leffler { 8339beb93cSSam Leffler struct wpa_ctrl_dst *dst, *prev = NULL; 8439beb93cSSam Leffler 8539beb93cSSam Leffler dst = priv->ctrl_dst; 8639beb93cSSam Leffler while (dst) { 8739beb93cSSam Leffler if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && 8839beb93cSSam Leffler from->sin_port == dst->addr.sin_port) { 8939beb93cSSam Leffler if (prev == NULL) 9039beb93cSSam Leffler priv->ctrl_dst = dst->next; 9139beb93cSSam Leffler else 9239beb93cSSam Leffler prev->next = dst->next; 9339beb93cSSam Leffler os_free(dst); 9439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached " 9539beb93cSSam Leffler "%s:%d", inet_ntoa(from->sin_addr), 9639beb93cSSam Leffler ntohs(from->sin_port)); 9739beb93cSSam Leffler return 0; 9839beb93cSSam Leffler } 9939beb93cSSam Leffler prev = dst; 10039beb93cSSam Leffler dst = dst->next; 10139beb93cSSam Leffler } 10239beb93cSSam Leffler return -1; 10339beb93cSSam Leffler } 10439beb93cSSam Leffler 10539beb93cSSam Leffler 10639beb93cSSam Leffler static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, 10739beb93cSSam Leffler struct sockaddr_in *from, 10839beb93cSSam Leffler socklen_t fromlen, 10939beb93cSSam Leffler char *level) 11039beb93cSSam Leffler { 11139beb93cSSam Leffler struct wpa_ctrl_dst *dst; 11239beb93cSSam Leffler 11339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 11439beb93cSSam Leffler 11539beb93cSSam Leffler dst = priv->ctrl_dst; 11639beb93cSSam Leffler while (dst) { 11739beb93cSSam Leffler if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && 11839beb93cSSam Leffler from->sin_port == dst->addr.sin_port) { 11939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor " 12039beb93cSSam Leffler "level %s:%d", inet_ntoa(from->sin_addr), 12139beb93cSSam Leffler ntohs(from->sin_port)); 12239beb93cSSam Leffler dst->debug_level = atoi(level); 12339beb93cSSam Leffler return 0; 12439beb93cSSam Leffler } 12539beb93cSSam Leffler dst = dst->next; 12639beb93cSSam Leffler } 12739beb93cSSam Leffler 12839beb93cSSam Leffler return -1; 12939beb93cSSam Leffler } 13039beb93cSSam Leffler 13139beb93cSSam Leffler 13239beb93cSSam Leffler static char * 13339beb93cSSam Leffler wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv, 13439beb93cSSam Leffler size_t *reply_len) 13539beb93cSSam Leffler { 13639beb93cSSam Leffler char *reply; 13739beb93cSSam Leffler reply = os_malloc(7 + 2 * COOKIE_LEN + 1); 13839beb93cSSam Leffler if (reply == NULL) { 13939beb93cSSam Leffler *reply_len = 1; 14039beb93cSSam Leffler return NULL; 14139beb93cSSam Leffler } 14239beb93cSSam Leffler 14339beb93cSSam Leffler os_memcpy(reply, "COOKIE=", 7); 14439beb93cSSam Leffler wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, 14539beb93cSSam Leffler priv->cookie, COOKIE_LEN); 14639beb93cSSam Leffler 14739beb93cSSam Leffler *reply_len = 7 + 2 * COOKIE_LEN; 14839beb93cSSam Leffler return reply; 14939beb93cSSam Leffler } 15039beb93cSSam Leffler 15139beb93cSSam Leffler 15239beb93cSSam Leffler static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, 15339beb93cSSam Leffler void *sock_ctx) 15439beb93cSSam Leffler { 15539beb93cSSam Leffler struct wpa_supplicant *wpa_s = eloop_ctx; 15639beb93cSSam Leffler struct ctrl_iface_priv *priv = sock_ctx; 15739beb93cSSam Leffler char buf[256], *pos; 15839beb93cSSam Leffler int res; 15939beb93cSSam Leffler struct sockaddr_in from; 16039beb93cSSam Leffler socklen_t fromlen = sizeof(from); 16139beb93cSSam Leffler char *reply = NULL; 16239beb93cSSam Leffler size_t reply_len = 0; 16339beb93cSSam Leffler int new_attached = 0; 16439beb93cSSam Leffler u8 cookie[COOKIE_LEN]; 16539beb93cSSam Leffler 16639beb93cSSam Leffler res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 16739beb93cSSam Leffler (struct sockaddr *) &from, &fromlen); 16839beb93cSSam Leffler if (res < 0) { 16939beb93cSSam Leffler perror("recvfrom(ctrl_iface)"); 17039beb93cSSam Leffler return; 17139beb93cSSam Leffler } 17239beb93cSSam Leffler if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { 17339beb93cSSam Leffler /* 17439beb93cSSam Leffler * The OS networking stack is expected to drop this kind of 17539beb93cSSam Leffler * frames since the socket is bound to only localhost address. 17639beb93cSSam Leffler * Just in case, drop the frame if it is coming from any other 17739beb93cSSam Leffler * address. 17839beb93cSSam Leffler */ 17939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " 18039beb93cSSam Leffler "source %s", inet_ntoa(from.sin_addr)); 18139beb93cSSam Leffler return; 18239beb93cSSam Leffler } 18339beb93cSSam Leffler buf[res] = '\0'; 18439beb93cSSam Leffler 18539beb93cSSam Leffler if (os_strcmp(buf, "GET_COOKIE") == 0) { 18639beb93cSSam Leffler reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len); 18739beb93cSSam Leffler goto done; 18839beb93cSSam Leffler } 18939beb93cSSam Leffler 19039beb93cSSam Leffler /* 19139beb93cSSam Leffler * Require that the client includes a prefix with the 'cookie' value 19239beb93cSSam Leffler * fetched with GET_COOKIE command. This is used to verify that the 19339beb93cSSam Leffler * client has access to a bidirectional link over UDP in order to 19439beb93cSSam Leffler * avoid attacks using forged localhost IP address even if the OS does 19539beb93cSSam Leffler * not block such frames from remote destinations. 19639beb93cSSam Leffler */ 19739beb93cSSam Leffler if (os_strncmp(buf, "COOKIE=", 7) != 0) { 19839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " 19939beb93cSSam Leffler "drop request"); 20039beb93cSSam Leffler return; 20139beb93cSSam Leffler } 20239beb93cSSam Leffler 20339beb93cSSam Leffler if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { 20439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " 20539beb93cSSam Leffler "request - drop request"); 20639beb93cSSam Leffler return; 20739beb93cSSam Leffler } 20839beb93cSSam Leffler 20939beb93cSSam Leffler if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { 21039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " 21139beb93cSSam Leffler "drop request"); 21239beb93cSSam Leffler return; 21339beb93cSSam Leffler } 21439beb93cSSam Leffler 21539beb93cSSam Leffler pos = buf + 7 + 2 * COOKIE_LEN; 21639beb93cSSam Leffler while (*pos == ' ') 21739beb93cSSam Leffler pos++; 21839beb93cSSam Leffler 21939beb93cSSam Leffler if (os_strcmp(pos, "ATTACH") == 0) { 22039beb93cSSam Leffler if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) 22139beb93cSSam Leffler reply_len = 1; 22239beb93cSSam Leffler else { 22339beb93cSSam Leffler new_attached = 1; 22439beb93cSSam Leffler reply_len = 2; 22539beb93cSSam Leffler } 22639beb93cSSam Leffler } else if (os_strcmp(pos, "DETACH") == 0) { 22739beb93cSSam Leffler if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) 22839beb93cSSam Leffler reply_len = 1; 22939beb93cSSam Leffler else 23039beb93cSSam Leffler reply_len = 2; 23139beb93cSSam Leffler } else if (os_strncmp(pos, "LEVEL ", 6) == 0) { 23239beb93cSSam Leffler if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, 23339beb93cSSam Leffler pos + 6)) 23439beb93cSSam Leffler reply_len = 1; 23539beb93cSSam Leffler else 23639beb93cSSam Leffler reply_len = 2; 23739beb93cSSam Leffler } else { 23839beb93cSSam Leffler reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos, 23939beb93cSSam Leffler &reply_len); 24039beb93cSSam Leffler } 24139beb93cSSam Leffler 24239beb93cSSam Leffler done: 24339beb93cSSam Leffler if (reply) { 24439beb93cSSam Leffler sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 24539beb93cSSam Leffler fromlen); 24639beb93cSSam Leffler os_free(reply); 24739beb93cSSam Leffler } else if (reply_len == 1) { 24839beb93cSSam Leffler sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 24939beb93cSSam Leffler fromlen); 25039beb93cSSam Leffler } else if (reply_len == 2) { 25139beb93cSSam Leffler sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, 25239beb93cSSam Leffler fromlen); 25339beb93cSSam Leffler } 25439beb93cSSam Leffler 25539beb93cSSam Leffler if (new_attached) 25639beb93cSSam Leffler eapol_sm_notify_ctrl_attached(wpa_s->eapol); 25739beb93cSSam Leffler } 25839beb93cSSam Leffler 25939beb93cSSam Leffler 26039beb93cSSam Leffler static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 26139beb93cSSam Leffler const char *txt, size_t len) 26239beb93cSSam Leffler { 26339beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 26439beb93cSSam Leffler if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 26539beb93cSSam Leffler return; 26639beb93cSSam Leffler wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 26739beb93cSSam Leffler } 26839beb93cSSam Leffler 26939beb93cSSam Leffler 27039beb93cSSam Leffler struct ctrl_iface_priv * 27139beb93cSSam Leffler wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 27239beb93cSSam Leffler { 27339beb93cSSam Leffler struct ctrl_iface_priv *priv; 27439beb93cSSam Leffler struct sockaddr_in addr; 27539beb93cSSam Leffler 27639beb93cSSam Leffler priv = os_zalloc(sizeof(*priv)); 27739beb93cSSam Leffler if (priv == NULL) 27839beb93cSSam Leffler return NULL; 27939beb93cSSam Leffler priv->wpa_s = wpa_s; 28039beb93cSSam Leffler priv->sock = -1; 28139beb93cSSam Leffler os_get_random(priv->cookie, COOKIE_LEN); 28239beb93cSSam Leffler 28339beb93cSSam Leffler if (wpa_s->conf->ctrl_interface == NULL) 28439beb93cSSam Leffler return priv; 28539beb93cSSam Leffler 28639beb93cSSam Leffler priv->sock = socket(PF_INET, SOCK_DGRAM, 0); 28739beb93cSSam Leffler if (priv->sock < 0) { 28839beb93cSSam Leffler perror("socket(PF_INET)"); 28939beb93cSSam Leffler goto fail; 29039beb93cSSam Leffler } 29139beb93cSSam Leffler 29239beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 29339beb93cSSam Leffler addr.sin_family = AF_INET; 29439beb93cSSam Leffler addr.sin_addr.s_addr = htonl((127 << 24) | 1); 29539beb93cSSam Leffler addr.sin_port = htons(WPA_CTRL_IFACE_PORT); 29639beb93cSSam Leffler if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 29739beb93cSSam Leffler perror("bind(AF_INET)"); 29839beb93cSSam Leffler goto fail; 29939beb93cSSam Leffler } 30039beb93cSSam Leffler 30139beb93cSSam Leffler eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, 30239beb93cSSam Leffler wpa_s, priv); 30339beb93cSSam Leffler wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 30439beb93cSSam Leffler 30539beb93cSSam Leffler return priv; 30639beb93cSSam Leffler 30739beb93cSSam Leffler fail: 30839beb93cSSam Leffler if (priv->sock >= 0) 30939beb93cSSam Leffler close(priv->sock); 31039beb93cSSam Leffler os_free(priv); 31139beb93cSSam Leffler return NULL; 31239beb93cSSam Leffler } 31339beb93cSSam Leffler 31439beb93cSSam Leffler 31539beb93cSSam Leffler void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 31639beb93cSSam Leffler { 31739beb93cSSam Leffler struct wpa_ctrl_dst *dst, *prev; 31839beb93cSSam Leffler 31939beb93cSSam Leffler if (priv->sock > -1) { 32039beb93cSSam Leffler eloop_unregister_read_sock(priv->sock); 32139beb93cSSam Leffler if (priv->ctrl_dst) { 32239beb93cSSam Leffler /* 32339beb93cSSam Leffler * Wait a second before closing the control socket if 32439beb93cSSam Leffler * there are any attached monitors in order to allow 32539beb93cSSam Leffler * them to receive any pending messages. 32639beb93cSSam Leffler */ 32739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " 32839beb93cSSam Leffler "monitors to receive messages"); 32939beb93cSSam Leffler os_sleep(1, 0); 33039beb93cSSam Leffler } 33139beb93cSSam Leffler close(priv->sock); 33239beb93cSSam Leffler priv->sock = -1; 33339beb93cSSam Leffler } 33439beb93cSSam Leffler 33539beb93cSSam Leffler dst = priv->ctrl_dst; 33639beb93cSSam Leffler while (dst) { 33739beb93cSSam Leffler prev = dst; 33839beb93cSSam Leffler dst = dst->next; 33939beb93cSSam Leffler os_free(prev); 34039beb93cSSam Leffler } 34139beb93cSSam Leffler os_free(priv); 34239beb93cSSam Leffler } 34339beb93cSSam Leffler 34439beb93cSSam Leffler 34539beb93cSSam Leffler static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 34639beb93cSSam Leffler int level, const char *buf, 34739beb93cSSam Leffler size_t len) 34839beb93cSSam Leffler { 34939beb93cSSam Leffler struct wpa_ctrl_dst *dst, *next; 35039beb93cSSam Leffler char levelstr[10]; 35139beb93cSSam Leffler int idx; 35239beb93cSSam Leffler char *sbuf; 35339beb93cSSam Leffler int llen; 35439beb93cSSam Leffler 35539beb93cSSam Leffler dst = priv->ctrl_dst; 35639beb93cSSam Leffler if (priv->sock < 0 || dst == NULL) 35739beb93cSSam Leffler return; 35839beb93cSSam Leffler 35939beb93cSSam Leffler os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 36039beb93cSSam Leffler 36139beb93cSSam Leffler llen = os_strlen(levelstr); 36239beb93cSSam Leffler sbuf = os_malloc(llen + len); 36339beb93cSSam Leffler if (sbuf == NULL) 36439beb93cSSam Leffler return; 36539beb93cSSam Leffler 36639beb93cSSam Leffler os_memcpy(sbuf, levelstr, llen); 36739beb93cSSam Leffler os_memcpy(sbuf + llen, buf, len); 36839beb93cSSam Leffler 36939beb93cSSam Leffler idx = 0; 37039beb93cSSam Leffler while (dst) { 37139beb93cSSam Leffler next = dst->next; 37239beb93cSSam Leffler if (level >= dst->debug_level) { 37339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", 37439beb93cSSam Leffler inet_ntoa(dst->addr.sin_addr), 37539beb93cSSam Leffler ntohs(dst->addr.sin_port)); 37639beb93cSSam Leffler if (sendto(priv->sock, sbuf, llen + len, 0, 37739beb93cSSam Leffler (struct sockaddr *) &dst->addr, 37839beb93cSSam Leffler sizeof(dst->addr)) < 0) { 37939beb93cSSam Leffler perror("sendto(CTRL_IFACE monitor)"); 38039beb93cSSam Leffler dst->errors++; 38139beb93cSSam Leffler if (dst->errors > 10) { 38239beb93cSSam Leffler wpa_supplicant_ctrl_iface_detach( 38339beb93cSSam Leffler priv, &dst->addr, 38439beb93cSSam Leffler dst->addrlen); 38539beb93cSSam Leffler } 38639beb93cSSam Leffler } else 38739beb93cSSam Leffler dst->errors = 0; 38839beb93cSSam Leffler } 38939beb93cSSam Leffler idx++; 39039beb93cSSam Leffler dst = next; 39139beb93cSSam Leffler } 39239beb93cSSam Leffler os_free(sbuf); 39339beb93cSSam Leffler } 39439beb93cSSam Leffler 39539beb93cSSam Leffler 39639beb93cSSam Leffler void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 39739beb93cSSam Leffler { 39839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 39939beb93cSSam Leffler priv->wpa_s->ifname); 40039beb93cSSam Leffler eloop_wait_for_read_sock(priv->sock); 40139beb93cSSam Leffler } 40239beb93cSSam Leffler 40339beb93cSSam Leffler 40439beb93cSSam Leffler /* Global ctrl_iface */ 40539beb93cSSam Leffler 40639beb93cSSam Leffler struct ctrl_iface_global_priv { 40739beb93cSSam Leffler int sock; 40839beb93cSSam Leffler u8 cookie[COOKIE_LEN]; 40939beb93cSSam Leffler }; 41039beb93cSSam Leffler 41139beb93cSSam Leffler 41239beb93cSSam Leffler static char * 41339beb93cSSam Leffler wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv, 41439beb93cSSam Leffler size_t *reply_len) 41539beb93cSSam Leffler { 41639beb93cSSam Leffler char *reply; 41739beb93cSSam Leffler reply = os_malloc(7 + 2 * COOKIE_LEN + 1); 41839beb93cSSam Leffler if (reply == NULL) { 41939beb93cSSam Leffler *reply_len = 1; 42039beb93cSSam Leffler return NULL; 42139beb93cSSam Leffler } 42239beb93cSSam Leffler 42339beb93cSSam Leffler os_memcpy(reply, "COOKIE=", 7); 42439beb93cSSam Leffler wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, 42539beb93cSSam Leffler priv->cookie, COOKIE_LEN); 42639beb93cSSam Leffler 42739beb93cSSam Leffler *reply_len = 7 + 2 * COOKIE_LEN; 42839beb93cSSam Leffler return reply; 42939beb93cSSam Leffler } 43039beb93cSSam Leffler 43139beb93cSSam Leffler 43239beb93cSSam Leffler static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, 43339beb93cSSam Leffler void *sock_ctx) 43439beb93cSSam Leffler { 43539beb93cSSam Leffler struct wpa_global *global = eloop_ctx; 43639beb93cSSam Leffler struct ctrl_iface_global_priv *priv = sock_ctx; 43739beb93cSSam Leffler char buf[256], *pos; 43839beb93cSSam Leffler int res; 43939beb93cSSam Leffler struct sockaddr_in from; 44039beb93cSSam Leffler socklen_t fromlen = sizeof(from); 44139beb93cSSam Leffler char *reply; 44239beb93cSSam Leffler size_t reply_len; 44339beb93cSSam Leffler u8 cookie[COOKIE_LEN]; 44439beb93cSSam Leffler 44539beb93cSSam Leffler res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 44639beb93cSSam Leffler (struct sockaddr *) &from, &fromlen); 44739beb93cSSam Leffler if (res < 0) { 44839beb93cSSam Leffler perror("recvfrom(ctrl_iface)"); 44939beb93cSSam Leffler return; 45039beb93cSSam Leffler } 45139beb93cSSam Leffler if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { 45239beb93cSSam Leffler /* 45339beb93cSSam Leffler * The OS networking stack is expected to drop this kind of 45439beb93cSSam Leffler * frames since the socket is bound to only localhost address. 45539beb93cSSam Leffler * Just in case, drop the frame if it is coming from any other 45639beb93cSSam Leffler * address. 45739beb93cSSam Leffler */ 45839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " 45939beb93cSSam Leffler "source %s", inet_ntoa(from.sin_addr)); 46039beb93cSSam Leffler return; 46139beb93cSSam Leffler } 46239beb93cSSam Leffler buf[res] = '\0'; 46339beb93cSSam Leffler 46439beb93cSSam Leffler if (os_strcmp(buf, "GET_COOKIE") == 0) { 46539beb93cSSam Leffler reply = wpa_supplicant_global_get_cookie(priv, &reply_len); 46639beb93cSSam Leffler goto done; 46739beb93cSSam Leffler } 46839beb93cSSam Leffler 46939beb93cSSam Leffler if (os_strncmp(buf, "COOKIE=", 7) != 0) { 47039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " 47139beb93cSSam Leffler "drop request"); 47239beb93cSSam Leffler return; 47339beb93cSSam Leffler } 47439beb93cSSam Leffler 47539beb93cSSam Leffler if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { 47639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " 47739beb93cSSam Leffler "request - drop request"); 47839beb93cSSam Leffler return; 47939beb93cSSam Leffler } 48039beb93cSSam Leffler 48139beb93cSSam Leffler if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { 48239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " 48339beb93cSSam Leffler "drop request"); 48439beb93cSSam Leffler return; 48539beb93cSSam Leffler } 48639beb93cSSam Leffler 48739beb93cSSam Leffler pos = buf + 7 + 2 * COOKIE_LEN; 48839beb93cSSam Leffler while (*pos == ' ') 48939beb93cSSam Leffler pos++; 49039beb93cSSam Leffler 49139beb93cSSam Leffler reply = wpa_supplicant_global_ctrl_iface_process(global, pos, 49239beb93cSSam Leffler &reply_len); 49339beb93cSSam Leffler 49439beb93cSSam Leffler done: 49539beb93cSSam Leffler if (reply) { 49639beb93cSSam Leffler sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 49739beb93cSSam Leffler fromlen); 49839beb93cSSam Leffler os_free(reply); 49939beb93cSSam Leffler } else if (reply_len) { 50039beb93cSSam Leffler sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 50139beb93cSSam Leffler fromlen); 50239beb93cSSam Leffler } 50339beb93cSSam Leffler } 50439beb93cSSam Leffler 50539beb93cSSam Leffler 50639beb93cSSam Leffler struct ctrl_iface_global_priv * 50739beb93cSSam Leffler wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 50839beb93cSSam Leffler { 50939beb93cSSam Leffler struct ctrl_iface_global_priv *priv; 51039beb93cSSam Leffler struct sockaddr_in addr; 51139beb93cSSam Leffler 51239beb93cSSam Leffler priv = os_zalloc(sizeof(*priv)); 51339beb93cSSam Leffler if (priv == NULL) 51439beb93cSSam Leffler return NULL; 51539beb93cSSam Leffler priv->sock = -1; 51639beb93cSSam Leffler os_get_random(priv->cookie, COOKIE_LEN); 51739beb93cSSam Leffler 51839beb93cSSam Leffler if (global->params.ctrl_interface == NULL) 51939beb93cSSam Leffler return priv; 52039beb93cSSam Leffler 52139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Global control interface '%s'", 52239beb93cSSam Leffler global->params.ctrl_interface); 52339beb93cSSam Leffler 52439beb93cSSam Leffler priv->sock = socket(PF_INET, SOCK_DGRAM, 0); 52539beb93cSSam Leffler if (priv->sock < 0) { 52639beb93cSSam Leffler perror("socket(PF_INET)"); 52739beb93cSSam Leffler goto fail; 52839beb93cSSam Leffler } 52939beb93cSSam Leffler 53039beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 53139beb93cSSam Leffler addr.sin_family = AF_INET; 53239beb93cSSam Leffler addr.sin_addr.s_addr = htonl((127 << 24) | 1); 53339beb93cSSam Leffler addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT); 53439beb93cSSam Leffler if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 53539beb93cSSam Leffler perror("bind(AF_INET)"); 53639beb93cSSam Leffler goto fail; 53739beb93cSSam Leffler } 53839beb93cSSam Leffler 53939beb93cSSam Leffler eloop_register_read_sock(priv->sock, 54039beb93cSSam Leffler wpa_supplicant_global_ctrl_iface_receive, 54139beb93cSSam Leffler global, priv); 54239beb93cSSam Leffler 54339beb93cSSam Leffler return priv; 54439beb93cSSam Leffler 54539beb93cSSam Leffler fail: 54639beb93cSSam Leffler if (priv->sock >= 0) 54739beb93cSSam Leffler close(priv->sock); 54839beb93cSSam Leffler os_free(priv); 54939beb93cSSam Leffler return NULL; 55039beb93cSSam Leffler } 55139beb93cSSam Leffler 55239beb93cSSam Leffler 55339beb93cSSam Leffler void 55439beb93cSSam Leffler wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 55539beb93cSSam Leffler { 55639beb93cSSam Leffler if (priv->sock >= 0) { 55739beb93cSSam Leffler eloop_unregister_read_sock(priv->sock); 55839beb93cSSam Leffler close(priv->sock); 55939beb93cSSam Leffler } 56039beb93cSSam Leffler os_free(priv); 56139beb93cSSam Leffler } 562