139beb93cSSam Leffler /* 239beb93cSSam Leffler * WPA Supplicant / privileged helper program 339beb93cSSam Leffler * Copyright (c) 2007-2009, 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 #ifdef __linux__ 1739beb93cSSam Leffler #include <fcntl.h> 1839beb93cSSam Leffler #endif /* __linux__ */ 1939beb93cSSam Leffler #include <sys/un.h> 2039beb93cSSam Leffler #include <sys/stat.h> 2139beb93cSSam Leffler 2239beb93cSSam Leffler #include "common.h" 2339beb93cSSam Leffler #include "eloop.h" 2439beb93cSSam Leffler #include "version.h" 2539beb93cSSam Leffler #include "drivers/driver.h" 2639beb93cSSam Leffler #include "l2_packet/l2_packet.h" 2739beb93cSSam Leffler #include "privsep_commands.h" 2839beb93cSSam Leffler #include "ieee802_11_defs.h" 2939beb93cSSam Leffler 3039beb93cSSam Leffler #ifndef ETH_P_EAPOL 3139beb93cSSam Leffler #define ETH_P_EAPOL 0x888e 3239beb93cSSam Leffler #endif 3339beb93cSSam Leffler 3439beb93cSSam Leffler #ifndef ETH_P_RSN_PREAUTH 3539beb93cSSam Leffler #define ETH_P_RSN_PREAUTH 0x88c7 3639beb93cSSam Leffler #endif 3739beb93cSSam Leffler 3839beb93cSSam Leffler 3939beb93cSSam Leffler struct wpa_priv_interface { 4039beb93cSSam Leffler struct wpa_priv_interface *next; 4139beb93cSSam Leffler char *driver_name; 4239beb93cSSam Leffler char *ifname; 4339beb93cSSam Leffler char *sock_name; 4439beb93cSSam Leffler int fd; 4539beb93cSSam Leffler 4639beb93cSSam Leffler struct wpa_driver_ops *driver; 4739beb93cSSam Leffler void *drv_priv; 4839beb93cSSam Leffler struct sockaddr_un drv_addr; 4939beb93cSSam Leffler int wpas_registered; 5039beb93cSSam Leffler 5139beb93cSSam Leffler /* TODO: add support for multiple l2 connections */ 5239beb93cSSam Leffler struct l2_packet_data *l2; 5339beb93cSSam Leffler struct sockaddr_un l2_addr; 5439beb93cSSam Leffler }; 5539beb93cSSam Leffler 5639beb93cSSam Leffler 5739beb93cSSam Leffler static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, 5839beb93cSSam Leffler struct sockaddr_un *from) 5939beb93cSSam Leffler { 6039beb93cSSam Leffler if (iface->drv_priv) { 6139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance"); 6239beb93cSSam Leffler if (iface->driver->set_wpa) 6339beb93cSSam Leffler iface->driver->set_wpa(iface->drv_priv, 0); 6439beb93cSSam Leffler if (iface->driver->deinit) 6539beb93cSSam Leffler iface->driver->deinit(iface->drv_priv); 6639beb93cSSam Leffler iface->drv_priv = NULL; 6739beb93cSSam Leffler iface->wpas_registered = 0; 6839beb93cSSam Leffler } 6939beb93cSSam Leffler 7039beb93cSSam Leffler if (iface->l2) { 7139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " 7239beb93cSSam Leffler "instance"); 7339beb93cSSam Leffler l2_packet_deinit(iface->l2); 7439beb93cSSam Leffler iface->l2 = NULL; 7539beb93cSSam Leffler } 7639beb93cSSam Leffler 7739beb93cSSam Leffler if (iface->driver->init == NULL) 7839beb93cSSam Leffler return; 7939beb93cSSam Leffler 8039beb93cSSam Leffler iface->drv_priv = iface->driver->init(iface, iface->ifname); 8139beb93cSSam Leffler if (iface->drv_priv == NULL) { 8239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to initialize driver wrapper"); 8339beb93cSSam Leffler return; 8439beb93cSSam Leffler } 8539beb93cSSam Leffler 8639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface " 8739beb93cSSam Leffler "'%s'", iface->driver_name, iface->ifname); 8839beb93cSSam Leffler 8939beb93cSSam Leffler os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr)); 9039beb93cSSam Leffler iface->wpas_registered = 1; 9139beb93cSSam Leffler 9239beb93cSSam Leffler if (iface->driver->set_param && 9339beb93cSSam Leffler iface->driver->set_param(iface->drv_priv, NULL) < 0) { 9439beb93cSSam Leffler wpa_printf(MSG_ERROR, "Driver interface rejected param"); 9539beb93cSSam Leffler } 9639beb93cSSam Leffler 9739beb93cSSam Leffler if (iface->driver->set_wpa) 9839beb93cSSam Leffler iface->driver->set_wpa(iface->drv_priv, 1); 9939beb93cSSam Leffler } 10039beb93cSSam Leffler 10139beb93cSSam Leffler 10239beb93cSSam Leffler static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface, 10339beb93cSSam Leffler struct sockaddr_un *from) 10439beb93cSSam Leffler { 10539beb93cSSam Leffler if (iface->drv_priv) { 10639beb93cSSam Leffler if (iface->driver->set_wpa) 10739beb93cSSam Leffler iface->driver->set_wpa(iface->drv_priv, 0); 10839beb93cSSam Leffler if (iface->driver->deinit) 10939beb93cSSam Leffler iface->driver->deinit(iface->drv_priv); 11039beb93cSSam Leffler iface->drv_priv = NULL; 11139beb93cSSam Leffler iface->wpas_registered = 0; 11239beb93cSSam Leffler } 11339beb93cSSam Leffler } 11439beb93cSSam Leffler 11539beb93cSSam Leffler 11639beb93cSSam Leffler static void wpa_priv_cmd_set_wpa(struct wpa_priv_interface *iface, 11739beb93cSSam Leffler char *buf, size_t len) 11839beb93cSSam Leffler { 11939beb93cSSam Leffler if (iface->drv_priv == NULL || len != sizeof(int)) 12039beb93cSSam Leffler return; 12139beb93cSSam Leffler 12239beb93cSSam Leffler if (iface->driver->set_wpa) 12339beb93cSSam Leffler iface->driver->set_wpa(iface->drv_priv, *((int *) buf)); 12439beb93cSSam Leffler } 12539beb93cSSam Leffler 12639beb93cSSam Leffler 12739beb93cSSam Leffler static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface, 12839beb93cSSam Leffler char *buf, size_t len) 12939beb93cSSam Leffler { 13039beb93cSSam Leffler if (iface->drv_priv == NULL) 13139beb93cSSam Leffler return; 13239beb93cSSam Leffler 13339beb93cSSam Leffler if (iface->driver->scan) 13439beb93cSSam Leffler iface->driver->scan(iface->drv_priv, len ? (u8 *) buf : NULL, 13539beb93cSSam Leffler len); 13639beb93cSSam Leffler } 13739beb93cSSam Leffler 13839beb93cSSam Leffler 13939beb93cSSam Leffler static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, 14039beb93cSSam Leffler struct sockaddr_un *from) 14139beb93cSSam Leffler { 14239beb93cSSam Leffler struct wpa_scan_results *res; 14339beb93cSSam Leffler u8 *buf = NULL, *pos, *end; 14439beb93cSSam Leffler int val; 14539beb93cSSam Leffler size_t i; 14639beb93cSSam Leffler 14739beb93cSSam Leffler res = iface->driver->get_scan_results2(iface->drv_priv); 14839beb93cSSam Leffler if (res == NULL) 14939beb93cSSam Leffler goto fail; 15039beb93cSSam Leffler 15139beb93cSSam Leffler buf = os_malloc(60000); 15239beb93cSSam Leffler if (buf == NULL) 15339beb93cSSam Leffler goto fail; 15439beb93cSSam Leffler pos = buf; 15539beb93cSSam Leffler end = buf + 60000; 15639beb93cSSam Leffler val = res->num; 15739beb93cSSam Leffler os_memcpy(pos, &val, sizeof(int)); 15839beb93cSSam Leffler pos += sizeof(int); 15939beb93cSSam Leffler 16039beb93cSSam Leffler for (i = 0; i < res->num; i++) { 16139beb93cSSam Leffler struct wpa_scan_res *r = res->res[i]; 16239beb93cSSam Leffler val = sizeof(*r) + r->ie_len; 16339beb93cSSam Leffler if (end - pos < (int) sizeof(int) + val) 16439beb93cSSam Leffler break; 16539beb93cSSam Leffler os_memcpy(pos, &val, sizeof(int)); 16639beb93cSSam Leffler pos += sizeof(int); 16739beb93cSSam Leffler os_memcpy(pos, r, val); 16839beb93cSSam Leffler pos += val; 16939beb93cSSam Leffler } 17039beb93cSSam Leffler 17139beb93cSSam Leffler sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, 17239beb93cSSam Leffler sizeof(*from)); 17339beb93cSSam Leffler 17439beb93cSSam Leffler os_free(buf); 17539beb93cSSam Leffler os_free(res); 17639beb93cSSam Leffler return; 17739beb93cSSam Leffler 17839beb93cSSam Leffler fail: 17939beb93cSSam Leffler os_free(buf); 18039beb93cSSam Leffler os_free(res); 18139beb93cSSam Leffler sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); 18239beb93cSSam Leffler } 18339beb93cSSam Leffler 18439beb93cSSam Leffler 18539beb93cSSam Leffler static void wpa_priv_send_old_scan_results(struct wpa_priv_interface *iface, 18639beb93cSSam Leffler struct sockaddr_un *from) 18739beb93cSSam Leffler { 18839beb93cSSam Leffler #define SCAN_AP_LIMIT 128 18939beb93cSSam Leffler int i, res, val; 19039beb93cSSam Leffler struct wpa_scan_result *results = NULL; 19139beb93cSSam Leffler u8 *buf = NULL, *pos, *end; 19239beb93cSSam Leffler struct wpa_scan_res nres; 19339beb93cSSam Leffler 19439beb93cSSam Leffler results = os_malloc(SCAN_AP_LIMIT * sizeof(*results)); 19539beb93cSSam Leffler if (results == NULL) 19639beb93cSSam Leffler goto fail; 19739beb93cSSam Leffler 19839beb93cSSam Leffler res = iface->driver->get_scan_results(iface->drv_priv, results, 19939beb93cSSam Leffler SCAN_AP_LIMIT); 20039beb93cSSam Leffler if (res < 0 || res > SCAN_AP_LIMIT) 20139beb93cSSam Leffler goto fail; 20239beb93cSSam Leffler 20339beb93cSSam Leffler buf = os_malloc(60000); 20439beb93cSSam Leffler if (buf == NULL) 20539beb93cSSam Leffler goto fail; 20639beb93cSSam Leffler pos = buf; 20739beb93cSSam Leffler end = buf + 60000; 20839beb93cSSam Leffler os_memcpy(pos, &res, sizeof(int)); 20939beb93cSSam Leffler pos += sizeof(int); 21039beb93cSSam Leffler 21139beb93cSSam Leffler os_memset(&nres, 0, sizeof(nres)); 21239beb93cSSam Leffler for (i = 0; i < res; i++) { 21339beb93cSSam Leffler struct wpa_scan_result *r = &results[i]; 21439beb93cSSam Leffler size_t ie_len; 21539beb93cSSam Leffler 21639beb93cSSam Leffler ie_len = 2 + r->ssid_len + r->rsn_ie_len + r->wpa_ie_len; 21739beb93cSSam Leffler if (r->maxrate) 21839beb93cSSam Leffler ie_len += 3; 21939beb93cSSam Leffler if (r->mdie_present) 22039beb93cSSam Leffler ie_len += 5; 22139beb93cSSam Leffler 22239beb93cSSam Leffler val = sizeof(nres) + ie_len; 22339beb93cSSam Leffler if (end - pos < (int) sizeof(int) + val) 22439beb93cSSam Leffler break; 22539beb93cSSam Leffler os_memcpy(pos, &val, sizeof(int)); 22639beb93cSSam Leffler pos += sizeof(int); 22739beb93cSSam Leffler 22839beb93cSSam Leffler os_memcpy(nres.bssid, r->bssid, ETH_ALEN); 22939beb93cSSam Leffler nres.freq = r->freq; 23039beb93cSSam Leffler nres.caps = r->caps; 23139beb93cSSam Leffler nres.qual = r->qual; 23239beb93cSSam Leffler nres.noise = r->noise; 23339beb93cSSam Leffler nres.level = r->level; 23439beb93cSSam Leffler nres.tsf = r->tsf; 23539beb93cSSam Leffler nres.ie_len = ie_len; 23639beb93cSSam Leffler 23739beb93cSSam Leffler os_memcpy(pos, &nres, sizeof(nres)); 23839beb93cSSam Leffler pos += sizeof(nres); 23939beb93cSSam Leffler 24039beb93cSSam Leffler /* SSID IE */ 24139beb93cSSam Leffler *pos++ = WLAN_EID_SSID; 24239beb93cSSam Leffler *pos++ = r->ssid_len; 24339beb93cSSam Leffler os_memcpy(pos, r->ssid, r->ssid_len); 24439beb93cSSam Leffler pos += r->ssid_len; 24539beb93cSSam Leffler 24639beb93cSSam Leffler if (r->maxrate) { 24739beb93cSSam Leffler /* Fake Supported Rate IE to include max rate */ 24839beb93cSSam Leffler *pos++ = WLAN_EID_SUPP_RATES; 24939beb93cSSam Leffler *pos++ = 1; 25039beb93cSSam Leffler *pos++ = r->maxrate; 25139beb93cSSam Leffler } 25239beb93cSSam Leffler 25339beb93cSSam Leffler if (r->rsn_ie_len) { 25439beb93cSSam Leffler os_memcpy(pos, r->rsn_ie, r->rsn_ie_len); 25539beb93cSSam Leffler pos += r->rsn_ie_len; 25639beb93cSSam Leffler } 25739beb93cSSam Leffler 25839beb93cSSam Leffler if (r->mdie_present) { 25939beb93cSSam Leffler os_memcpy(pos, r->mdie, 5); 26039beb93cSSam Leffler pos += 5; 26139beb93cSSam Leffler } 26239beb93cSSam Leffler 26339beb93cSSam Leffler if (r->wpa_ie_len) { 26439beb93cSSam Leffler os_memcpy(pos, r->wpa_ie, r->wpa_ie_len); 26539beb93cSSam Leffler pos += r->wpa_ie_len; 26639beb93cSSam Leffler } 26739beb93cSSam Leffler } 26839beb93cSSam Leffler 26939beb93cSSam Leffler sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, 27039beb93cSSam Leffler sizeof(*from)); 27139beb93cSSam Leffler 27239beb93cSSam Leffler os_free(buf); 27339beb93cSSam Leffler os_free(results); 27439beb93cSSam Leffler return; 27539beb93cSSam Leffler 27639beb93cSSam Leffler fail: 27739beb93cSSam Leffler os_free(buf); 27839beb93cSSam Leffler os_free(results); 27939beb93cSSam Leffler sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); 28039beb93cSSam Leffler } 28139beb93cSSam Leffler 28239beb93cSSam Leffler 28339beb93cSSam Leffler static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface, 28439beb93cSSam Leffler struct sockaddr_un *from) 28539beb93cSSam Leffler { 28639beb93cSSam Leffler if (iface->drv_priv == NULL) 28739beb93cSSam Leffler return; 28839beb93cSSam Leffler 28939beb93cSSam Leffler if (iface->driver->get_scan_results2) 29039beb93cSSam Leffler wpa_priv_get_scan_results2(iface, from); 29139beb93cSSam Leffler else if (iface->driver->get_scan_results) 29239beb93cSSam Leffler wpa_priv_send_old_scan_results(iface, from); 29339beb93cSSam Leffler else 29439beb93cSSam Leffler sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, 29539beb93cSSam Leffler sizeof(*from)); 29639beb93cSSam Leffler } 29739beb93cSSam Leffler 29839beb93cSSam Leffler 29939beb93cSSam Leffler static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface, 30039beb93cSSam Leffler void *buf, size_t len) 30139beb93cSSam Leffler { 30239beb93cSSam Leffler struct wpa_driver_associate_params params; 30339beb93cSSam Leffler struct privsep_cmd_associate *assoc; 30439beb93cSSam Leffler u8 *bssid; 30539beb93cSSam Leffler int res; 30639beb93cSSam Leffler 30739beb93cSSam Leffler if (iface->drv_priv == NULL || iface->driver->associate == NULL) 30839beb93cSSam Leffler return; 30939beb93cSSam Leffler 31039beb93cSSam Leffler if (len < sizeof(*assoc)) { 31139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Invalid association request"); 31239beb93cSSam Leffler return; 31339beb93cSSam Leffler } 31439beb93cSSam Leffler 31539beb93cSSam Leffler assoc = buf; 31639beb93cSSam Leffler if (sizeof(*assoc) + assoc->wpa_ie_len > len) { 31739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Association request overflow"); 31839beb93cSSam Leffler return; 31939beb93cSSam Leffler } 32039beb93cSSam Leffler 32139beb93cSSam Leffler os_memset(¶ms, 0, sizeof(params)); 32239beb93cSSam Leffler bssid = assoc->bssid; 32339beb93cSSam Leffler if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5]) 32439beb93cSSam Leffler params.bssid = bssid; 32539beb93cSSam Leffler params.ssid = assoc->ssid; 32639beb93cSSam Leffler if (assoc->ssid_len > 32) 32739beb93cSSam Leffler return; 32839beb93cSSam Leffler params.ssid_len = assoc->ssid_len; 32939beb93cSSam Leffler params.freq = assoc->freq; 33039beb93cSSam Leffler if (assoc->wpa_ie_len) { 33139beb93cSSam Leffler params.wpa_ie = (u8 *) (assoc + 1); 33239beb93cSSam Leffler params.wpa_ie_len = assoc->wpa_ie_len; 33339beb93cSSam Leffler } 33439beb93cSSam Leffler params.pairwise_suite = assoc->pairwise_suite; 33539beb93cSSam Leffler params.group_suite = assoc->group_suite; 33639beb93cSSam Leffler params.key_mgmt_suite = assoc->key_mgmt_suite; 33739beb93cSSam Leffler params.auth_alg = assoc->auth_alg; 33839beb93cSSam Leffler params.mode = assoc->mode; 33939beb93cSSam Leffler 34039beb93cSSam Leffler res = iface->driver->associate(iface->drv_priv, ¶ms); 34139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "drv->associate: res=%d", res); 34239beb93cSSam Leffler } 34339beb93cSSam Leffler 34439beb93cSSam Leffler 34539beb93cSSam Leffler static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface, 34639beb93cSSam Leffler struct sockaddr_un *from) 34739beb93cSSam Leffler { 34839beb93cSSam Leffler u8 bssid[ETH_ALEN]; 34939beb93cSSam Leffler 35039beb93cSSam Leffler if (iface->drv_priv == NULL) 35139beb93cSSam Leffler goto fail; 35239beb93cSSam Leffler 35339beb93cSSam Leffler if (iface->driver->get_bssid == NULL || 35439beb93cSSam Leffler iface->driver->get_bssid(iface->drv_priv, bssid) < 0) 35539beb93cSSam Leffler goto fail; 35639beb93cSSam Leffler 35739beb93cSSam Leffler sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from, 35839beb93cSSam Leffler sizeof(*from)); 35939beb93cSSam Leffler return; 36039beb93cSSam Leffler 36139beb93cSSam Leffler fail: 36239beb93cSSam Leffler sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); 36339beb93cSSam Leffler } 36439beb93cSSam Leffler 36539beb93cSSam Leffler 36639beb93cSSam Leffler static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface, 36739beb93cSSam Leffler struct sockaddr_un *from) 36839beb93cSSam Leffler { 36939beb93cSSam Leffler u8 ssid[sizeof(int) + 32]; 37039beb93cSSam Leffler int res; 37139beb93cSSam Leffler 37239beb93cSSam Leffler if (iface->drv_priv == NULL) 37339beb93cSSam Leffler goto fail; 37439beb93cSSam Leffler 37539beb93cSSam Leffler if (iface->driver->get_ssid == NULL) 37639beb93cSSam Leffler goto fail; 37739beb93cSSam Leffler 37839beb93cSSam Leffler res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]); 37939beb93cSSam Leffler if (res < 0 || res > 32) 38039beb93cSSam Leffler goto fail; 38139beb93cSSam Leffler os_memcpy(ssid, &res, sizeof(int)); 38239beb93cSSam Leffler 38339beb93cSSam Leffler sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from, 38439beb93cSSam Leffler sizeof(*from)); 38539beb93cSSam Leffler return; 38639beb93cSSam Leffler 38739beb93cSSam Leffler fail: 38839beb93cSSam Leffler sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); 38939beb93cSSam Leffler } 39039beb93cSSam Leffler 39139beb93cSSam Leffler 39239beb93cSSam Leffler static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface, 39339beb93cSSam Leffler void *buf, size_t len) 39439beb93cSSam Leffler { 39539beb93cSSam Leffler struct privsep_cmd_set_key *params; 39639beb93cSSam Leffler int res; 39739beb93cSSam Leffler 39839beb93cSSam Leffler if (iface->drv_priv == NULL || iface->driver->set_key == NULL) 39939beb93cSSam Leffler return; 40039beb93cSSam Leffler 40139beb93cSSam Leffler if (len != sizeof(*params)) { 40239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Invalid set_key request"); 40339beb93cSSam Leffler return; 40439beb93cSSam Leffler } 40539beb93cSSam Leffler 40639beb93cSSam Leffler params = buf; 40739beb93cSSam Leffler 40839beb93cSSam Leffler res = iface->driver->set_key(iface->drv_priv, params->alg, 40939beb93cSSam Leffler params->addr, params->key_idx, 41039beb93cSSam Leffler params->set_tx, 41139beb93cSSam Leffler params->seq_len ? params->seq : NULL, 41239beb93cSSam Leffler params->seq_len, 41339beb93cSSam Leffler params->key_len ? params->key : NULL, 41439beb93cSSam Leffler params->key_len); 41539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res); 41639beb93cSSam Leffler } 41739beb93cSSam Leffler 41839beb93cSSam Leffler 41939beb93cSSam Leffler static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface, 42039beb93cSSam Leffler struct sockaddr_un *from) 42139beb93cSSam Leffler { 42239beb93cSSam Leffler struct wpa_driver_capa capa; 42339beb93cSSam Leffler 42439beb93cSSam Leffler if (iface->drv_priv == NULL) 42539beb93cSSam Leffler goto fail; 42639beb93cSSam Leffler 42739beb93cSSam Leffler if (iface->driver->get_capa == NULL || 42839beb93cSSam Leffler iface->driver->get_capa(iface->drv_priv, &capa) < 0) 42939beb93cSSam Leffler goto fail; 43039beb93cSSam Leffler 43139beb93cSSam Leffler sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from, 43239beb93cSSam Leffler sizeof(*from)); 43339beb93cSSam Leffler return; 43439beb93cSSam Leffler 43539beb93cSSam Leffler fail: 43639beb93cSSam Leffler sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); 43739beb93cSSam Leffler } 43839beb93cSSam Leffler 43939beb93cSSam Leffler 44039beb93cSSam Leffler static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf, 44139beb93cSSam Leffler size_t len) 44239beb93cSSam Leffler { 44339beb93cSSam Leffler struct wpa_priv_interface *iface = ctx; 44439beb93cSSam Leffler struct msghdr msg; 44539beb93cSSam Leffler struct iovec io[2]; 44639beb93cSSam Leffler 44739beb93cSSam Leffler io[0].iov_base = (u8 *) src_addr; 44839beb93cSSam Leffler io[0].iov_len = ETH_ALEN; 44939beb93cSSam Leffler io[1].iov_base = (u8 *) buf; 45039beb93cSSam Leffler io[1].iov_len = len; 45139beb93cSSam Leffler 45239beb93cSSam Leffler os_memset(&msg, 0, sizeof(msg)); 45339beb93cSSam Leffler msg.msg_iov = io; 45439beb93cSSam Leffler msg.msg_iovlen = 2; 45539beb93cSSam Leffler msg.msg_name = &iface->l2_addr; 45639beb93cSSam Leffler msg.msg_namelen = sizeof(iface->l2_addr); 45739beb93cSSam Leffler 45839beb93cSSam Leffler if (sendmsg(iface->fd, &msg, 0) < 0) { 45939beb93cSSam Leffler perror("sendmsg(l2 rx)"); 46039beb93cSSam Leffler } 46139beb93cSSam Leffler } 46239beb93cSSam Leffler 46339beb93cSSam Leffler 46439beb93cSSam Leffler static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface, 46539beb93cSSam Leffler struct sockaddr_un *from, 46639beb93cSSam Leffler void *buf, size_t len) 46739beb93cSSam Leffler { 46839beb93cSSam Leffler int *reg_cmd = buf; 46939beb93cSSam Leffler u8 own_addr[ETH_ALEN]; 47039beb93cSSam Leffler int res; 47139beb93cSSam Leffler u16 proto; 47239beb93cSSam Leffler 47339beb93cSSam Leffler if (len != 2 * sizeof(int)) { 47439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu", 47539beb93cSSam Leffler (unsigned long) len); 47639beb93cSSam Leffler return; 47739beb93cSSam Leffler } 47839beb93cSSam Leffler 47939beb93cSSam Leffler proto = reg_cmd[0]; 48039beb93cSSam Leffler if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) { 48139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Refused l2_packet connection for " 48239beb93cSSam Leffler "ethertype 0x%x", proto); 48339beb93cSSam Leffler return; 48439beb93cSSam Leffler } 48539beb93cSSam Leffler 48639beb93cSSam Leffler if (iface->l2) { 48739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " 48839beb93cSSam Leffler "instance"); 48939beb93cSSam Leffler l2_packet_deinit(iface->l2); 49039beb93cSSam Leffler iface->l2 = NULL; 49139beb93cSSam Leffler } 49239beb93cSSam Leffler 49339beb93cSSam Leffler os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr)); 49439beb93cSSam Leffler 49539beb93cSSam Leffler iface->l2 = l2_packet_init(iface->ifname, NULL, proto, 49639beb93cSSam Leffler wpa_priv_l2_rx, iface, reg_cmd[1]); 49739beb93cSSam Leffler if (iface->l2 == NULL) { 49839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet " 49939beb93cSSam Leffler "instance for protocol %d", proto); 50039beb93cSSam Leffler return; 50139beb93cSSam Leffler } 50239beb93cSSam Leffler 50339beb93cSSam Leffler if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) { 50439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to get own address from " 50539beb93cSSam Leffler "l2_packet"); 50639beb93cSSam Leffler l2_packet_deinit(iface->l2); 50739beb93cSSam Leffler iface->l2 = NULL; 50839beb93cSSam Leffler return; 50939beb93cSSam Leffler } 51039beb93cSSam Leffler 51139beb93cSSam Leffler res = sendto(iface->fd, own_addr, ETH_ALEN, 0, 51239beb93cSSam Leffler (struct sockaddr *) from, sizeof(*from)); 51339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res); 51439beb93cSSam Leffler } 51539beb93cSSam Leffler 51639beb93cSSam Leffler 51739beb93cSSam Leffler static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface, 51839beb93cSSam Leffler struct sockaddr_un *from) 51939beb93cSSam Leffler { 52039beb93cSSam Leffler if (iface->l2) { 52139beb93cSSam Leffler l2_packet_deinit(iface->l2); 52239beb93cSSam Leffler iface->l2 = NULL; 52339beb93cSSam Leffler } 52439beb93cSSam Leffler } 52539beb93cSSam Leffler 52639beb93cSSam Leffler 52739beb93cSSam Leffler static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface, 52839beb93cSSam Leffler struct sockaddr_un *from) 52939beb93cSSam Leffler { 53039beb93cSSam Leffler if (iface->l2) 53139beb93cSSam Leffler l2_packet_notify_auth_start(iface->l2); 53239beb93cSSam Leffler } 53339beb93cSSam Leffler 53439beb93cSSam Leffler 53539beb93cSSam Leffler static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface, 53639beb93cSSam Leffler struct sockaddr_un *from, 53739beb93cSSam Leffler void *buf, size_t len) 53839beb93cSSam Leffler { 53939beb93cSSam Leffler u8 *dst_addr; 54039beb93cSSam Leffler u16 proto; 54139beb93cSSam Leffler int res; 54239beb93cSSam Leffler 54339beb93cSSam Leffler if (iface->l2 == NULL) 54439beb93cSSam Leffler return; 54539beb93cSSam Leffler 54639beb93cSSam Leffler if (len < ETH_ALEN + 2) { 54739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Too short L2 send packet (len=%lu)", 54839beb93cSSam Leffler (unsigned long) len); 54939beb93cSSam Leffler return; 55039beb93cSSam Leffler } 55139beb93cSSam Leffler 55239beb93cSSam Leffler dst_addr = buf; 55339beb93cSSam Leffler os_memcpy(&proto, buf + ETH_ALEN, 2); 55439beb93cSSam Leffler 55539beb93cSSam Leffler if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) { 55639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype " 55739beb93cSSam Leffler "0x%x", proto); 55839beb93cSSam Leffler return; 55939beb93cSSam Leffler } 56039beb93cSSam Leffler 56139beb93cSSam Leffler res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2, 56239beb93cSSam Leffler len - ETH_ALEN - 2); 56339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "L2 send: res=%d", res); 56439beb93cSSam Leffler } 56539beb93cSSam Leffler 56639beb93cSSam Leffler 56739beb93cSSam Leffler static void wpa_priv_cmd_set_mode(struct wpa_priv_interface *iface, 56839beb93cSSam Leffler void *buf, size_t len) 56939beb93cSSam Leffler { 57039beb93cSSam Leffler if (iface->drv_priv == NULL || iface->driver->set_mode == NULL || 57139beb93cSSam Leffler len != sizeof(int)) 57239beb93cSSam Leffler return; 57339beb93cSSam Leffler 57439beb93cSSam Leffler iface->driver->set_mode(iface->drv_priv, *((int *) buf)); 57539beb93cSSam Leffler } 57639beb93cSSam Leffler 57739beb93cSSam Leffler 57839beb93cSSam Leffler static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface, 57939beb93cSSam Leffler char *buf) 58039beb93cSSam Leffler { 58139beb93cSSam Leffler if (iface->drv_priv == NULL || iface->driver->set_country == NULL || 58239beb93cSSam Leffler *buf == '\0') 58339beb93cSSam Leffler return; 58439beb93cSSam Leffler 58539beb93cSSam Leffler iface->driver->set_country(iface->drv_priv, buf); 58639beb93cSSam Leffler } 58739beb93cSSam Leffler 58839beb93cSSam Leffler 58939beb93cSSam Leffler static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx) 59039beb93cSSam Leffler { 59139beb93cSSam Leffler struct wpa_priv_interface *iface = eloop_ctx; 59239beb93cSSam Leffler char buf[2000], *pos; 59339beb93cSSam Leffler void *cmd_buf; 59439beb93cSSam Leffler size_t cmd_len; 59539beb93cSSam Leffler int res, cmd; 59639beb93cSSam Leffler struct sockaddr_un from; 59739beb93cSSam Leffler socklen_t fromlen = sizeof(from); 59839beb93cSSam Leffler 59939beb93cSSam Leffler res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from, 60039beb93cSSam Leffler &fromlen); 60139beb93cSSam Leffler if (res < 0) { 60239beb93cSSam Leffler perror("recvfrom"); 60339beb93cSSam Leffler return; 60439beb93cSSam Leffler } 60539beb93cSSam Leffler 60639beb93cSSam Leffler if (res < (int) sizeof(int)) { 60739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Too short command (len=%d)", res); 60839beb93cSSam Leffler return; 60939beb93cSSam Leffler } 61039beb93cSSam Leffler 61139beb93cSSam Leffler os_memcpy(&cmd, buf, sizeof(int)); 61239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Command %d for interface %s", 61339beb93cSSam Leffler cmd, iface->ifname); 61439beb93cSSam Leffler cmd_buf = &buf[sizeof(int)]; 61539beb93cSSam Leffler cmd_len = res - sizeof(int); 61639beb93cSSam Leffler 61739beb93cSSam Leffler switch (cmd) { 61839beb93cSSam Leffler case PRIVSEP_CMD_REGISTER: 61939beb93cSSam Leffler wpa_priv_cmd_register(iface, &from); 62039beb93cSSam Leffler break; 62139beb93cSSam Leffler case PRIVSEP_CMD_UNREGISTER: 62239beb93cSSam Leffler wpa_priv_cmd_unregister(iface, &from); 62339beb93cSSam Leffler break; 62439beb93cSSam Leffler case PRIVSEP_CMD_SET_WPA: 62539beb93cSSam Leffler wpa_priv_cmd_set_wpa(iface, cmd_buf, cmd_len); 62639beb93cSSam Leffler break; 62739beb93cSSam Leffler case PRIVSEP_CMD_SCAN: 62839beb93cSSam Leffler wpa_priv_cmd_scan(iface, cmd_buf, cmd_len); 62939beb93cSSam Leffler break; 63039beb93cSSam Leffler case PRIVSEP_CMD_GET_SCAN_RESULTS: 63139beb93cSSam Leffler wpa_priv_cmd_get_scan_results(iface, &from); 63239beb93cSSam Leffler break; 63339beb93cSSam Leffler case PRIVSEP_CMD_ASSOCIATE: 63439beb93cSSam Leffler wpa_priv_cmd_associate(iface, cmd_buf, cmd_len); 63539beb93cSSam Leffler break; 63639beb93cSSam Leffler case PRIVSEP_CMD_GET_BSSID: 63739beb93cSSam Leffler wpa_priv_cmd_get_bssid(iface, &from); 63839beb93cSSam Leffler break; 63939beb93cSSam Leffler case PRIVSEP_CMD_GET_SSID: 64039beb93cSSam Leffler wpa_priv_cmd_get_ssid(iface, &from); 64139beb93cSSam Leffler break; 64239beb93cSSam Leffler case PRIVSEP_CMD_SET_KEY: 64339beb93cSSam Leffler wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len); 64439beb93cSSam Leffler break; 64539beb93cSSam Leffler case PRIVSEP_CMD_GET_CAPA: 64639beb93cSSam Leffler wpa_priv_cmd_get_capa(iface, &from); 64739beb93cSSam Leffler break; 64839beb93cSSam Leffler case PRIVSEP_CMD_L2_REGISTER: 64939beb93cSSam Leffler wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len); 65039beb93cSSam Leffler break; 65139beb93cSSam Leffler case PRIVSEP_CMD_L2_UNREGISTER: 65239beb93cSSam Leffler wpa_priv_cmd_l2_unregister(iface, &from); 65339beb93cSSam Leffler break; 65439beb93cSSam Leffler case PRIVSEP_CMD_L2_NOTIFY_AUTH_START: 65539beb93cSSam Leffler wpa_priv_cmd_l2_notify_auth_start(iface, &from); 65639beb93cSSam Leffler break; 65739beb93cSSam Leffler case PRIVSEP_CMD_L2_SEND: 65839beb93cSSam Leffler wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len); 65939beb93cSSam Leffler break; 66039beb93cSSam Leffler case PRIVSEP_CMD_SET_MODE: 66139beb93cSSam Leffler wpa_priv_cmd_set_mode(iface, cmd_buf, cmd_len); 66239beb93cSSam Leffler break; 66339beb93cSSam Leffler case PRIVSEP_CMD_SET_COUNTRY: 66439beb93cSSam Leffler pos = cmd_buf; 66539beb93cSSam Leffler if (pos + cmd_len >= buf + sizeof(buf)) 66639beb93cSSam Leffler break; 66739beb93cSSam Leffler pos[cmd_len] = '\0'; 66839beb93cSSam Leffler wpa_priv_cmd_set_country(iface, pos); 66939beb93cSSam Leffler break; 67039beb93cSSam Leffler } 67139beb93cSSam Leffler } 67239beb93cSSam Leffler 67339beb93cSSam Leffler 67439beb93cSSam Leffler static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) 67539beb93cSSam Leffler { 67639beb93cSSam Leffler if (iface->drv_priv && iface->driver->deinit) 67739beb93cSSam Leffler iface->driver->deinit(iface->drv_priv); 67839beb93cSSam Leffler 67939beb93cSSam Leffler if (iface->fd >= 0) { 68039beb93cSSam Leffler eloop_unregister_read_sock(iface->fd); 68139beb93cSSam Leffler close(iface->fd); 68239beb93cSSam Leffler unlink(iface->sock_name); 68339beb93cSSam Leffler } 68439beb93cSSam Leffler 68539beb93cSSam Leffler if (iface->l2) 68639beb93cSSam Leffler l2_packet_deinit(iface->l2); 68739beb93cSSam Leffler 68839beb93cSSam Leffler os_free(iface->ifname); 68939beb93cSSam Leffler os_free(iface->driver_name); 69039beb93cSSam Leffler os_free(iface->sock_name); 69139beb93cSSam Leffler os_free(iface); 69239beb93cSSam Leffler } 69339beb93cSSam Leffler 69439beb93cSSam Leffler 69539beb93cSSam Leffler extern struct wpa_driver_ops *wpa_supplicant_drivers[]; 69639beb93cSSam Leffler 69739beb93cSSam Leffler static struct wpa_priv_interface * 69839beb93cSSam Leffler wpa_priv_interface_init(const char *dir, const char *params) 69939beb93cSSam Leffler { 70039beb93cSSam Leffler struct wpa_priv_interface *iface; 70139beb93cSSam Leffler char *pos; 70239beb93cSSam Leffler size_t len; 70339beb93cSSam Leffler struct sockaddr_un addr; 70439beb93cSSam Leffler int i; 70539beb93cSSam Leffler 70639beb93cSSam Leffler pos = os_strchr(params, ':'); 70739beb93cSSam Leffler if (pos == NULL) 70839beb93cSSam Leffler return NULL; 70939beb93cSSam Leffler 71039beb93cSSam Leffler iface = os_zalloc(sizeof(*iface)); 71139beb93cSSam Leffler if (iface == NULL) 71239beb93cSSam Leffler return NULL; 71339beb93cSSam Leffler iface->fd = -1; 71439beb93cSSam Leffler 71539beb93cSSam Leffler len = pos - params; 71639beb93cSSam Leffler iface->driver_name = os_malloc(len + 1); 71739beb93cSSam Leffler if (iface->driver_name == NULL) { 71839beb93cSSam Leffler wpa_priv_interface_deinit(iface); 71939beb93cSSam Leffler return NULL; 72039beb93cSSam Leffler } 72139beb93cSSam Leffler os_memcpy(iface->driver_name, params, len); 72239beb93cSSam Leffler iface->driver_name[len] = '\0'; 72339beb93cSSam Leffler 72439beb93cSSam Leffler for (i = 0; wpa_supplicant_drivers[i]; i++) { 72539beb93cSSam Leffler if (os_strcmp(iface->driver_name, 72639beb93cSSam Leffler wpa_supplicant_drivers[i]->name) == 0) { 72739beb93cSSam Leffler iface->driver = wpa_supplicant_drivers[i]; 72839beb93cSSam Leffler break; 72939beb93cSSam Leffler } 73039beb93cSSam Leffler } 73139beb93cSSam Leffler if (iface->driver == NULL) { 73239beb93cSSam Leffler wpa_printf(MSG_ERROR, "Unsupported driver '%s'", 73339beb93cSSam Leffler iface->driver_name); 73439beb93cSSam Leffler wpa_priv_interface_deinit(iface); 73539beb93cSSam Leffler return NULL; 73639beb93cSSam Leffler } 73739beb93cSSam Leffler 73839beb93cSSam Leffler pos++; 73939beb93cSSam Leffler iface->ifname = os_strdup(pos); 74039beb93cSSam Leffler if (iface->ifname == NULL) { 74139beb93cSSam Leffler wpa_priv_interface_deinit(iface); 74239beb93cSSam Leffler return NULL; 74339beb93cSSam Leffler } 74439beb93cSSam Leffler 74539beb93cSSam Leffler len = os_strlen(dir) + 1 + os_strlen(iface->ifname); 74639beb93cSSam Leffler iface->sock_name = os_malloc(len + 1); 74739beb93cSSam Leffler if (iface->sock_name == NULL) { 74839beb93cSSam Leffler wpa_priv_interface_deinit(iface); 74939beb93cSSam Leffler return NULL; 75039beb93cSSam Leffler } 75139beb93cSSam Leffler 75239beb93cSSam Leffler os_snprintf(iface->sock_name, len + 1, "%s/%s", dir, iface->ifname); 75339beb93cSSam Leffler if (os_strlen(iface->sock_name) >= sizeof(addr.sun_path)) { 75439beb93cSSam Leffler wpa_priv_interface_deinit(iface); 75539beb93cSSam Leffler return NULL; 75639beb93cSSam Leffler } 75739beb93cSSam Leffler 75839beb93cSSam Leffler iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0); 75939beb93cSSam Leffler if (iface->fd < 0) { 76039beb93cSSam Leffler perror("socket(PF_UNIX)"); 76139beb93cSSam Leffler wpa_priv_interface_deinit(iface); 76239beb93cSSam Leffler return NULL; 76339beb93cSSam Leffler } 76439beb93cSSam Leffler 76539beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 76639beb93cSSam Leffler addr.sun_family = AF_UNIX; 76739beb93cSSam Leffler os_strlcpy(addr.sun_path, iface->sock_name, sizeof(addr.sun_path)); 76839beb93cSSam Leffler 76939beb93cSSam Leffler if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 77039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "bind(PF_UNIX) failed: %s", 77139beb93cSSam Leffler strerror(errno)); 77239beb93cSSam Leffler if (connect(iface->fd, (struct sockaddr *) &addr, 77339beb93cSSam Leffler sizeof(addr)) < 0) { 77439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Socket exists, but does not " 77539beb93cSSam Leffler "allow connections - assuming it was " 77639beb93cSSam Leffler "leftover from forced program termination"); 77739beb93cSSam Leffler if (unlink(iface->sock_name) < 0) { 77839beb93cSSam Leffler perror("unlink[ctrl_iface]"); 77939beb93cSSam Leffler wpa_printf(MSG_ERROR, "Could not unlink " 78039beb93cSSam Leffler "existing ctrl_iface socket '%s'", 78139beb93cSSam Leffler iface->sock_name); 78239beb93cSSam Leffler goto fail; 78339beb93cSSam Leffler } 78439beb93cSSam Leffler if (bind(iface->fd, (struct sockaddr *) &addr, 78539beb93cSSam Leffler sizeof(addr)) < 0) { 78639beb93cSSam Leffler perror("bind(PF_UNIX)"); 78739beb93cSSam Leffler goto fail; 78839beb93cSSam Leffler } 78939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 79039beb93cSSam Leffler "socket '%s'", iface->sock_name); 79139beb93cSSam Leffler } else { 79239beb93cSSam Leffler wpa_printf(MSG_INFO, "Socket exists and seems to be " 79339beb93cSSam Leffler "in use - cannot override it"); 79439beb93cSSam Leffler wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 79539beb93cSSam Leffler "not used anymore", iface->sock_name); 79639beb93cSSam Leffler goto fail; 79739beb93cSSam Leffler } 79839beb93cSSam Leffler } 79939beb93cSSam Leffler 80039beb93cSSam Leffler if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { 80139beb93cSSam Leffler perror("chmod"); 80239beb93cSSam Leffler goto fail; 80339beb93cSSam Leffler } 80439beb93cSSam Leffler 80539beb93cSSam Leffler eloop_register_read_sock(iface->fd, wpa_priv_receive, iface, NULL); 80639beb93cSSam Leffler 80739beb93cSSam Leffler return iface; 80839beb93cSSam Leffler 80939beb93cSSam Leffler fail: 81039beb93cSSam Leffler wpa_priv_interface_deinit(iface); 81139beb93cSSam Leffler return NULL; 81239beb93cSSam Leffler } 81339beb93cSSam Leffler 81439beb93cSSam Leffler 81539beb93cSSam Leffler static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event, 81639beb93cSSam Leffler const void *data, size_t data_len) 81739beb93cSSam Leffler { 81839beb93cSSam Leffler struct msghdr msg; 81939beb93cSSam Leffler struct iovec io[2]; 82039beb93cSSam Leffler 82139beb93cSSam Leffler io[0].iov_base = &event; 82239beb93cSSam Leffler io[0].iov_len = sizeof(event); 82339beb93cSSam Leffler io[1].iov_base = (u8 *) data; 82439beb93cSSam Leffler io[1].iov_len = data_len; 82539beb93cSSam Leffler 82639beb93cSSam Leffler os_memset(&msg, 0, sizeof(msg)); 82739beb93cSSam Leffler msg.msg_iov = io; 82839beb93cSSam Leffler msg.msg_iovlen = data ? 2 : 1; 82939beb93cSSam Leffler msg.msg_name = &iface->drv_addr; 83039beb93cSSam Leffler msg.msg_namelen = sizeof(iface->drv_addr); 83139beb93cSSam Leffler 83239beb93cSSam Leffler if (sendmsg(iface->fd, &msg, 0) < 0) { 83339beb93cSSam Leffler perror("sendmsg(wpas_socket)"); 83439beb93cSSam Leffler return -1; 83539beb93cSSam Leffler } 83639beb93cSSam Leffler 83739beb93cSSam Leffler return 0; 83839beb93cSSam Leffler } 83939beb93cSSam Leffler 84039beb93cSSam Leffler 84139beb93cSSam Leffler static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event, 84239beb93cSSam Leffler union wpa_event_data *data) 84339beb93cSSam Leffler { 84439beb93cSSam Leffler size_t buflen = 3 * sizeof(int); 84539beb93cSSam Leffler u8 *buf, *pos; 84639beb93cSSam Leffler int len; 84739beb93cSSam Leffler 84839beb93cSSam Leffler if (data) { 84939beb93cSSam Leffler buflen += data->assoc_info.req_ies_len + 85039beb93cSSam Leffler data->assoc_info.resp_ies_len + 85139beb93cSSam Leffler data->assoc_info.beacon_ies_len; 85239beb93cSSam Leffler } 85339beb93cSSam Leffler 85439beb93cSSam Leffler buf = os_malloc(buflen); 85539beb93cSSam Leffler if (buf == NULL) 85639beb93cSSam Leffler return; 85739beb93cSSam Leffler 85839beb93cSSam Leffler pos = buf; 85939beb93cSSam Leffler 86039beb93cSSam Leffler if (data && data->assoc_info.req_ies) { 86139beb93cSSam Leffler len = data->assoc_info.req_ies_len; 86239beb93cSSam Leffler os_memcpy(pos, &len, sizeof(int)); 86339beb93cSSam Leffler pos += sizeof(int); 86439beb93cSSam Leffler os_memcpy(pos, data->assoc_info.req_ies, len); 86539beb93cSSam Leffler pos += len; 86639beb93cSSam Leffler } else { 86739beb93cSSam Leffler len = 0; 86839beb93cSSam Leffler os_memcpy(pos, &len, sizeof(int)); 86939beb93cSSam Leffler pos += sizeof(int); 87039beb93cSSam Leffler } 87139beb93cSSam Leffler 87239beb93cSSam Leffler if (data && data->assoc_info.resp_ies) { 87339beb93cSSam Leffler len = data->assoc_info.resp_ies_len; 87439beb93cSSam Leffler os_memcpy(pos, &len, sizeof(int)); 87539beb93cSSam Leffler pos += sizeof(int); 87639beb93cSSam Leffler os_memcpy(pos, data->assoc_info.resp_ies, len); 87739beb93cSSam Leffler pos += len; 87839beb93cSSam Leffler } else { 87939beb93cSSam Leffler len = 0; 88039beb93cSSam Leffler os_memcpy(pos, &len, sizeof(int)); 88139beb93cSSam Leffler pos += sizeof(int); 88239beb93cSSam Leffler } 88339beb93cSSam Leffler 88439beb93cSSam Leffler if (data && data->assoc_info.beacon_ies) { 88539beb93cSSam Leffler len = data->assoc_info.beacon_ies_len; 88639beb93cSSam Leffler os_memcpy(pos, &len, sizeof(int)); 88739beb93cSSam Leffler pos += sizeof(int); 88839beb93cSSam Leffler os_memcpy(pos, data->assoc_info.beacon_ies, len); 88939beb93cSSam Leffler pos += len; 89039beb93cSSam Leffler } else { 89139beb93cSSam Leffler len = 0; 89239beb93cSSam Leffler os_memcpy(pos, &len, sizeof(int)); 89339beb93cSSam Leffler pos += sizeof(int); 89439beb93cSSam Leffler } 89539beb93cSSam Leffler 89639beb93cSSam Leffler wpa_priv_send_event(iface, event, buf, buflen); 89739beb93cSSam Leffler 89839beb93cSSam Leffler os_free(buf); 89939beb93cSSam Leffler } 90039beb93cSSam Leffler 90139beb93cSSam Leffler 90239beb93cSSam Leffler static void wpa_priv_send_interface_status(struct wpa_priv_interface *iface, 90339beb93cSSam Leffler union wpa_event_data *data) 90439beb93cSSam Leffler { 90539beb93cSSam Leffler int ievent; 90639beb93cSSam Leffler size_t len, maxlen; 90739beb93cSSam Leffler u8 *buf; 90839beb93cSSam Leffler char *ifname; 90939beb93cSSam Leffler 91039beb93cSSam Leffler if (data == NULL) 91139beb93cSSam Leffler return; 91239beb93cSSam Leffler 91339beb93cSSam Leffler ievent = data->interface_status.ievent; 91439beb93cSSam Leffler maxlen = sizeof(data->interface_status.ifname); 91539beb93cSSam Leffler ifname = data->interface_status.ifname; 91639beb93cSSam Leffler for (len = 0; len < maxlen && ifname[len]; len++) 91739beb93cSSam Leffler ; 91839beb93cSSam Leffler 91939beb93cSSam Leffler buf = os_malloc(sizeof(int) + len); 92039beb93cSSam Leffler if (buf == NULL) 92139beb93cSSam Leffler return; 92239beb93cSSam Leffler 92339beb93cSSam Leffler os_memcpy(buf, &ievent, sizeof(int)); 92439beb93cSSam Leffler os_memcpy(buf + sizeof(int), ifname, len); 92539beb93cSSam Leffler 92639beb93cSSam Leffler wpa_priv_send_event(iface, PRIVSEP_EVENT_INTERFACE_STATUS, 92739beb93cSSam Leffler buf, sizeof(int) + len); 92839beb93cSSam Leffler 92939beb93cSSam Leffler os_free(buf); 93039beb93cSSam Leffler 93139beb93cSSam Leffler } 93239beb93cSSam Leffler 93339beb93cSSam Leffler 93439beb93cSSam Leffler static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface, 93539beb93cSSam Leffler union wpa_event_data *data) 93639beb93cSSam Leffler { 93739beb93cSSam Leffler size_t len; 93839beb93cSSam Leffler u8 *buf, *pos; 93939beb93cSSam Leffler 94039beb93cSSam Leffler if (data == NULL || data->ft_ies.ies == NULL) 94139beb93cSSam Leffler return; 94239beb93cSSam Leffler 94339beb93cSSam Leffler len = sizeof(int) + ETH_ALEN + data->ft_ies.ies_len; 94439beb93cSSam Leffler buf = os_malloc(len); 94539beb93cSSam Leffler if (buf == NULL) 94639beb93cSSam Leffler return; 94739beb93cSSam Leffler 94839beb93cSSam Leffler pos = buf; 94939beb93cSSam Leffler os_memcpy(pos, &data->ft_ies.ft_action, sizeof(int)); 95039beb93cSSam Leffler pos += sizeof(int); 95139beb93cSSam Leffler os_memcpy(pos, data->ft_ies.target_ap, ETH_ALEN); 95239beb93cSSam Leffler pos += ETH_ALEN; 95339beb93cSSam Leffler os_memcpy(pos, data->ft_ies.ies, data->ft_ies.ies_len); 95439beb93cSSam Leffler 95539beb93cSSam Leffler wpa_priv_send_event(iface, PRIVSEP_EVENT_FT_RESPONSE, buf, len); 95639beb93cSSam Leffler 95739beb93cSSam Leffler os_free(buf); 95839beb93cSSam Leffler 95939beb93cSSam Leffler } 96039beb93cSSam Leffler 96139beb93cSSam Leffler 96239beb93cSSam Leffler void wpa_supplicant_event(void *ctx, wpa_event_type event, 96339beb93cSSam Leffler union wpa_event_data *data) 96439beb93cSSam Leffler { 96539beb93cSSam Leffler struct wpa_priv_interface *iface = ctx; 96639beb93cSSam Leffler 96739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - event=%d", __func__, event); 96839beb93cSSam Leffler 96939beb93cSSam Leffler if (!iface->wpas_registered) { 97039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Driver event received, but " 97139beb93cSSam Leffler "wpa_supplicant not registered"); 97239beb93cSSam Leffler return; 97339beb93cSSam Leffler } 97439beb93cSSam Leffler 97539beb93cSSam Leffler switch (event) { 97639beb93cSSam Leffler case EVENT_ASSOC: 97739beb93cSSam Leffler wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOC, data); 97839beb93cSSam Leffler break; 97939beb93cSSam Leffler case EVENT_DISASSOC: 98039beb93cSSam Leffler wpa_priv_send_event(iface, PRIVSEP_EVENT_DISASSOC, NULL, 0); 98139beb93cSSam Leffler break; 98239beb93cSSam Leffler case EVENT_ASSOCINFO: 98339beb93cSSam Leffler if (data == NULL) 98439beb93cSSam Leffler return; 98539beb93cSSam Leffler wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOCINFO, data); 98639beb93cSSam Leffler break; 98739beb93cSSam Leffler case EVENT_MICHAEL_MIC_FAILURE: 98839beb93cSSam Leffler if (data == NULL) 98939beb93cSSam Leffler return; 99039beb93cSSam Leffler wpa_priv_send_event(iface, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE, 99139beb93cSSam Leffler &data->michael_mic_failure.unicast, 99239beb93cSSam Leffler sizeof(int)); 99339beb93cSSam Leffler break; 99439beb93cSSam Leffler case EVENT_SCAN_RESULTS: 99539beb93cSSam Leffler wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_RESULTS, NULL, 99639beb93cSSam Leffler 0); 99739beb93cSSam Leffler break; 99839beb93cSSam Leffler case EVENT_INTERFACE_STATUS: 99939beb93cSSam Leffler wpa_priv_send_interface_status(iface, data); 100039beb93cSSam Leffler break; 100139beb93cSSam Leffler case EVENT_PMKID_CANDIDATE: 100239beb93cSSam Leffler if (data == NULL) 100339beb93cSSam Leffler return; 100439beb93cSSam Leffler wpa_priv_send_event(iface, PRIVSEP_EVENT_PMKID_CANDIDATE, 100539beb93cSSam Leffler &data->pmkid_candidate, 100639beb93cSSam Leffler sizeof(struct pmkid_candidate)); 100739beb93cSSam Leffler break; 100839beb93cSSam Leffler case EVENT_STKSTART: 100939beb93cSSam Leffler if (data == NULL) 101039beb93cSSam Leffler return; 101139beb93cSSam Leffler wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART, 101239beb93cSSam Leffler &data->stkstart.peer, ETH_ALEN); 101339beb93cSSam Leffler break; 101439beb93cSSam Leffler case EVENT_FT_RESPONSE: 101539beb93cSSam Leffler wpa_priv_send_ft_response(iface, data); 101639beb93cSSam Leffler break; 101739beb93cSSam Leffler default: 101839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Unsupported driver event %d - TODO", 101939beb93cSSam Leffler event); 102039beb93cSSam Leffler break; 102139beb93cSSam Leffler } 102239beb93cSSam Leffler } 102339beb93cSSam Leffler 102439beb93cSSam Leffler 102539beb93cSSam Leffler void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, 102639beb93cSSam Leffler const u8 *buf, size_t len) 102739beb93cSSam Leffler { 102839beb93cSSam Leffler struct wpa_priv_interface *iface = ctx; 102939beb93cSSam Leffler struct msghdr msg; 103039beb93cSSam Leffler struct iovec io[3]; 103139beb93cSSam Leffler int event = PRIVSEP_EVENT_RX_EAPOL; 103239beb93cSSam Leffler 103339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RX EAPOL from driver"); 103439beb93cSSam Leffler io[0].iov_base = &event; 103539beb93cSSam Leffler io[0].iov_len = sizeof(event); 103639beb93cSSam Leffler io[1].iov_base = (u8 *) src_addr; 103739beb93cSSam Leffler io[1].iov_len = ETH_ALEN; 103839beb93cSSam Leffler io[2].iov_base = (u8 *) buf; 103939beb93cSSam Leffler io[2].iov_len = len; 104039beb93cSSam Leffler 104139beb93cSSam Leffler os_memset(&msg, 0, sizeof(msg)); 104239beb93cSSam Leffler msg.msg_iov = io; 104339beb93cSSam Leffler msg.msg_iovlen = 3; 104439beb93cSSam Leffler msg.msg_name = &iface->drv_addr; 104539beb93cSSam Leffler msg.msg_namelen = sizeof(iface->drv_addr); 104639beb93cSSam Leffler 104739beb93cSSam Leffler if (sendmsg(iface->fd, &msg, 0) < 0) 104839beb93cSSam Leffler perror("sendmsg(wpas_socket)"); 104939beb93cSSam Leffler } 105039beb93cSSam Leffler 105139beb93cSSam Leffler 105239beb93cSSam Leffler #ifdef CONFIG_CLIENT_MLME 105339beb93cSSam Leffler void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features, 105439beb93cSSam Leffler size_t num_hw_features) 105539beb93cSSam Leffler { 105639beb93cSSam Leffler size_t i; 105739beb93cSSam Leffler 105839beb93cSSam Leffler if (hw_features == NULL) 105939beb93cSSam Leffler return; 106039beb93cSSam Leffler 106139beb93cSSam Leffler for (i = 0; i < num_hw_features; i++) { 106239beb93cSSam Leffler os_free(hw_features[i].channels); 106339beb93cSSam Leffler os_free(hw_features[i].rates); 106439beb93cSSam Leffler } 106539beb93cSSam Leffler 106639beb93cSSam Leffler os_free(hw_features); 106739beb93cSSam Leffler } 106839beb93cSSam Leffler 106939beb93cSSam Leffler 107039beb93cSSam Leffler void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len, 107139beb93cSSam Leffler struct ieee80211_rx_status *rx_status) 107239beb93cSSam Leffler { 107339beb93cSSam Leffler struct wpa_priv_interface *iface = ctx; 107439beb93cSSam Leffler struct msghdr msg; 107539beb93cSSam Leffler struct iovec io[3]; 107639beb93cSSam Leffler int event = PRIVSEP_EVENT_STA_RX; 107739beb93cSSam Leffler 107839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "STA RX from driver"); 107939beb93cSSam Leffler io[0].iov_base = &event; 108039beb93cSSam Leffler io[0].iov_len = sizeof(event); 108139beb93cSSam Leffler io[1].iov_base = (u8 *) rx_status; 108239beb93cSSam Leffler io[1].iov_len = sizeof(*rx_status); 108339beb93cSSam Leffler io[2].iov_base = (u8 *) buf; 108439beb93cSSam Leffler io[2].iov_len = len; 108539beb93cSSam Leffler 108639beb93cSSam Leffler os_memset(&msg, 0, sizeof(msg)); 108739beb93cSSam Leffler msg.msg_iov = io; 108839beb93cSSam Leffler msg.msg_iovlen = 3; 108939beb93cSSam Leffler msg.msg_name = &iface->drv_addr; 109039beb93cSSam Leffler msg.msg_namelen = sizeof(iface->drv_addr); 109139beb93cSSam Leffler 109239beb93cSSam Leffler if (sendmsg(iface->fd, &msg, 0) < 0) 109339beb93cSSam Leffler perror("sendmsg(wpas_socket)"); 109439beb93cSSam Leffler } 109539beb93cSSam Leffler #endif /* CONFIG_CLIENT_MLME */ 109639beb93cSSam Leffler 109739beb93cSSam Leffler 109839beb93cSSam Leffler static void wpa_priv_terminate(int sig, void *eloop_ctx, void *signal_ctx) 109939beb93cSSam Leffler { 110039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "wpa_priv termination requested"); 110139beb93cSSam Leffler eloop_terminate(); 110239beb93cSSam Leffler } 110339beb93cSSam Leffler 110439beb93cSSam Leffler 110539beb93cSSam Leffler static void wpa_priv_fd_workaround(void) 110639beb93cSSam Leffler { 110739beb93cSSam Leffler #ifdef __linux__ 110839beb93cSSam Leffler int s, i; 110939beb93cSSam Leffler /* When started from pcmcia-cs scripts, wpa_supplicant might start with 111039beb93cSSam Leffler * fd 0, 1, and 2 closed. This will cause some issues because many 111139beb93cSSam Leffler * places in wpa_supplicant are still printing out to stdout. As a 111239beb93cSSam Leffler * workaround, make sure that fd's 0, 1, and 2 are not used for other 111339beb93cSSam Leffler * sockets. */ 111439beb93cSSam Leffler for (i = 0; i < 3; i++) { 111539beb93cSSam Leffler s = open("/dev/null", O_RDWR); 111639beb93cSSam Leffler if (s > 2) { 111739beb93cSSam Leffler close(s); 111839beb93cSSam Leffler break; 111939beb93cSSam Leffler } 112039beb93cSSam Leffler } 112139beb93cSSam Leffler #endif /* __linux__ */ 112239beb93cSSam Leffler } 112339beb93cSSam Leffler 112439beb93cSSam Leffler 112539beb93cSSam Leffler static void usage(void) 112639beb93cSSam Leffler { 112739beb93cSSam Leffler printf("wpa_priv v" VERSION_STR "\n" 112839beb93cSSam Leffler "Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> and " 112939beb93cSSam Leffler "contributors\n" 113039beb93cSSam Leffler "\n" 113139beb93cSSam Leffler "usage:\n" 113239beb93cSSam Leffler " wpa_priv [-Bdd] [-P<pid file>] <driver:ifname> " 113339beb93cSSam Leffler "[driver:ifname ...]\n"); 113439beb93cSSam Leffler } 113539beb93cSSam Leffler 113639beb93cSSam Leffler 113739beb93cSSam Leffler extern int wpa_debug_level; 113839beb93cSSam Leffler 113939beb93cSSam Leffler int main(int argc, char *argv[]) 114039beb93cSSam Leffler { 114139beb93cSSam Leffler int c, i; 114239beb93cSSam Leffler int ret = -1; 114339beb93cSSam Leffler char *pid_file = NULL; 114439beb93cSSam Leffler int daemonize = 0; 114539beb93cSSam Leffler char *ctrl_dir = "/var/run/wpa_priv"; 114639beb93cSSam Leffler struct wpa_priv_interface *interfaces = NULL, *iface; 114739beb93cSSam Leffler 114839beb93cSSam Leffler if (os_program_init()) 114939beb93cSSam Leffler return -1; 115039beb93cSSam Leffler 115139beb93cSSam Leffler wpa_priv_fd_workaround(); 115239beb93cSSam Leffler 115339beb93cSSam Leffler for (;;) { 115439beb93cSSam Leffler c = getopt(argc, argv, "Bc:dP:"); 115539beb93cSSam Leffler if (c < 0) 115639beb93cSSam Leffler break; 115739beb93cSSam Leffler switch (c) { 115839beb93cSSam Leffler case 'B': 115939beb93cSSam Leffler daemonize++; 116039beb93cSSam Leffler break; 116139beb93cSSam Leffler case 'c': 116239beb93cSSam Leffler ctrl_dir = optarg; 116339beb93cSSam Leffler break; 116439beb93cSSam Leffler case 'd': 116539beb93cSSam Leffler wpa_debug_level--; 116639beb93cSSam Leffler break; 116739beb93cSSam Leffler case 'P': 116839beb93cSSam Leffler pid_file = os_rel2abs_path(optarg); 116939beb93cSSam Leffler break; 117039beb93cSSam Leffler default: 117139beb93cSSam Leffler usage(); 117239beb93cSSam Leffler goto out; 117339beb93cSSam Leffler } 117439beb93cSSam Leffler } 117539beb93cSSam Leffler 117639beb93cSSam Leffler if (optind >= argc) { 117739beb93cSSam Leffler usage(); 117839beb93cSSam Leffler goto out; 117939beb93cSSam Leffler } 118039beb93cSSam Leffler 118139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "wpa_priv control directory: '%s'", ctrl_dir); 118239beb93cSSam Leffler 118339beb93cSSam Leffler if (eloop_init(NULL)) { 118439beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to initialize event loop"); 118539beb93cSSam Leffler goto out; 118639beb93cSSam Leffler } 118739beb93cSSam Leffler 118839beb93cSSam Leffler for (i = optind; i < argc; i++) { 118939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]); 119039beb93cSSam Leffler iface = wpa_priv_interface_init(ctrl_dir, argv[i]); 119139beb93cSSam Leffler if (iface == NULL) 119239beb93cSSam Leffler goto out; 119339beb93cSSam Leffler iface->next = interfaces; 119439beb93cSSam Leffler interfaces = iface; 119539beb93cSSam Leffler } 119639beb93cSSam Leffler 119739beb93cSSam Leffler if (daemonize && os_daemonize(pid_file)) 119839beb93cSSam Leffler goto out; 119939beb93cSSam Leffler 120039beb93cSSam Leffler eloop_register_signal_terminate(wpa_priv_terminate, NULL); 120139beb93cSSam Leffler eloop_run(); 120239beb93cSSam Leffler 120339beb93cSSam Leffler ret = 0; 120439beb93cSSam Leffler 120539beb93cSSam Leffler out: 120639beb93cSSam Leffler iface = interfaces; 120739beb93cSSam Leffler while (iface) { 120839beb93cSSam Leffler struct wpa_priv_interface *prev = iface; 120939beb93cSSam Leffler iface = iface->next; 121039beb93cSSam Leffler wpa_priv_interface_deinit(prev); 121139beb93cSSam Leffler } 121239beb93cSSam Leffler 121339beb93cSSam Leffler eloop_destroy(); 121439beb93cSSam Leffler 121539beb93cSSam Leffler os_daemonize_terminate(pid_file); 121639beb93cSSam Leffler os_free(pid_file); 121739beb93cSSam Leffler os_program_deinit(); 121839beb93cSSam Leffler 121939beb93cSSam Leffler return ret; 122039beb93cSSam Leffler } 1221