diff options
165 files changed, 4682 insertions, 4469 deletions
@@ -1,7 +1,7 @@ wpa_supplicant and hostapd -------------------------- -Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. These programs are licensed under the BSD license (the one with diff --git a/hostapd/Android.mk b/hostapd/Android.mk index bc0273e0..6e37beb4 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -137,10 +137,10 @@ OBJS += src/eapol_auth/eapol_auth_sm.c ifndef CONFIG_NO_DUMP_STATE -# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to -# a file (undefine it, if you want to save in binary size) +# define HOSTAPD_DUMP_STATE to include support for dumping internal state +# through control interface commands (undefine it, if you want to save in +# binary size) L_CFLAGS += -DHOSTAPD_DUMP_STATE -OBJS += dump_state.c OBJS += src/eapol_auth/eapol_auth_dump.c endif @@ -351,7 +351,7 @@ ifdef CONFIG_EAP_GPSK L_CFLAGS += -DEAP_SERVER_GPSK OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c ifdef CONFIG_EAP_GPSK_SHA256 -L_CFLAGS += -DEAP_SERVER_GPSK_SHA256 +L_CFLAGS += -DEAP_GPSK_SHA256 endif NEED_SHA256=y NEED_AES_OMAC1=y diff --git a/hostapd/Makefile b/hostapd/Makefile index ae96d35d..5fd64810 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -6,8 +6,8 @@ ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif -CFLAGS += -I../src -CFLAGS += -I../src/utils +CFLAGS += -I$(abspath ../src) +CFLAGS += -I$(abspath ../src/utils) # Uncomment following line and set the path to your kernel tree include # directory if your C library does not include all header files. @@ -15,6 +15,11 @@ CFLAGS += -I../src/utils -include .config +ifdef CONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_TESTING_OPTIONS +CONFIG_WPS_TESTING=y +endif + ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS CONFIG_OS=win32 @@ -114,10 +119,10 @@ LIBS_n += -lgcov endif ifndef CONFIG_NO_DUMP_STATE -# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to -# a file (undefine it, if you want to save in binary size) +# define HOSTAPD_DUMP_STATE to include support for dumping internal state +# through control interface commands (undefine it, if you want to save in +# binary size) CFLAGS += -DHOSTAPD_DUMP_STATE -OBJS += dump_state.o OBJS += ../src/eapol_auth/eapol_auth_dump.o endif @@ -327,7 +332,7 @@ ifdef CONFIG_EAP_GPSK CFLAGS += -DEAP_SERVER_GPSK OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o ifdef CONFIG_EAP_GPSK_SHA256 -CFLAGS += -DEAP_SERVER_GPSK_SHA256 +CFLAGS += -DEAP_GPSK_SHA256 endif NEED_SHA256=y NEED_AES_OMAC1=y @@ -858,10 +863,6 @@ LIBS += -lsqlite3 LIBS_h += -lsqlite3 endif -ifdef CONFIG_TESTING_OPTIONS -CFLAGS += -DCONFIG_TESTING_OPTIONS -endif - ALL=hostapd hostapd_cli all: verify_config $(ALL) @@ -873,9 +874,15 @@ Q= E=true endif +ifdef CONFIG_CODE_COVERAGE +%.o: %.c + @$(E) " CC " $< + $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<) +else %.o: %.c $(Q)$(CC) -c -o $@ $(CFLAGS) $< @$(E) " CC " $< +endif verify_config: @if [ ! -r .config ]; then \ @@ -944,9 +951,15 @@ hlr_auc_gw: $(HOBJS) $(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h) @$(E) " LD " $@ +lcov-html: + lcov -c -d .. > lcov.info + genhtml lcov.info --output-directory lcov-html + clean: $(MAKE) -C ../src clean rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw rm -f *.d *.gcno *.gcda *.gcov + rm -f lcov.info + rm -rf lcov-html -include $(OBJS:%.o=%.d) diff --git a/hostapd/README b/hostapd/README index 39b70cab..50868ee1 100644 --- a/hostapd/README +++ b/hostapd/README @@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator and RADIUS authentication server ================================================================ -Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/hostapd/android.config b/hostapd/android.config index f51a5bfe..33e96c48 100644 --- a/hostapd/android.config +++ b/hostapd/android.config @@ -157,7 +157,7 @@ CONFIG_NO_RADIUS=y # Remove support for VLANs #CONFIG_NO_VLAN=y -# Remove support for dumping state into a file on SIGUSR1 signal +# Remove support for dumping internal state through control interface commands # This can be used to reduce binary size at the cost of disabling a debugging # option. #CONFIG_NO_DUMP_STATE=y diff --git a/hostapd/config_file.c b/hostapd/config_file.c index ae059176..41988345 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -22,9 +22,6 @@ #include "config_file.h" -extern struct wpa_driver_ops *wpa_drivers[]; - - #ifndef CONFIG_NO_VLAN static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, const char *fname) @@ -1634,7 +1631,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "logger_stdout") == 0) { bss->logger_stdout = atoi(pos); } else if (os_strcmp(buf, "dump_file") == 0) { - bss->dump_log_name = os_strdup(pos); + wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore", + line); } else if (os_strcmp(buf, "ssid") == 0) { bss->ssid.ssid_len = os_strlen(pos); if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN || diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 2d0379f3..72faeaea 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1,6 +1,6 @@ /* * hostapd / UNIX domain socket -based control interface - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -20,6 +20,7 @@ #include "common/ieee802_11_defs.h" #include "drivers/driver.h" #include "radius/radius_client.h" +#include "radius/radius_server.h" #include "ap/hostapd.h" #include "ap/ap_config.h" #include "ap/ieee802_1x.h" @@ -29,6 +30,7 @@ #include "ap/wps_hostapd.h" #include "ap/ctrl_iface_ap.h" #include "ap/ap_drv_ops.h" +#include "ap/wnm_ap.h" #include "ap/wpa_auth.h" #include "wps/wps_defs.h" #include "wps/wps.h" @@ -665,9 +667,8 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, const char *cmd) { u8 addr[ETH_ALEN]; - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; int disassoc_timer; + struct sta_info *sta; if (hwaddr_aton(cmd, addr)) return -1; @@ -675,31 +676,15 @@ static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, return -1; disassoc_timer = atoi(cmd + 17); - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = - host_to_le16(disassoc_timer); - mgmt->u.action.u.bss_tm_req.validity_interval = 0; - - pos = mgmt->u.action.u.bss_tm_req.variable; - - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for disassociation imminent message", + MAC2STR(addr)); return -1; } - return 0; + return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); } @@ -708,14 +693,20 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, { u8 addr[ETH_ALEN]; const char *url, *timerstr; - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; - size_t url_len; int disassoc_timer; + struct sta_info *sta; if (hwaddr_aton(cmd, addr)) return -1; + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for ESS disassociation imminent message", + MAC2STR(addr)); + return -1; + } + timerstr = cmd + 17; if (*timerstr != ' ') return -1; @@ -728,76 +719,8 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, if (url == NULL) return -1; url++; - url_len = os_strlen(url); - if (url_len > 255) - return -1; - - os_memset(buf, 0, sizeof(buf)); - mgmt = (struct ieee80211_mgmt *) buf; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; - mgmt->u.action.u.bss_tm_req.dialog_token = 1; - mgmt->u.action.u.bss_tm_req.req_mode = - WNM_BSS_TM_REQ_DISASSOC_IMMINENT | - WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = - host_to_le16(disassoc_timer); - mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; - - pos = mgmt->u.action.u.bss_tm_req.variable; - - /* Session Information URL */ - *pos++ = url_len; - os_memcpy(pos, url, url_len); - pos += url_len; - - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { - wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " - "Management Request frame"); - return -1; - } - - /* send disassociation frame after time-out */ - if (disassoc_timer) { - struct sta_info *sta; - int timeout, beacon_int; - - /* - * Prevent STA from reconnecting using cached PMKSA to force - * full authentication with the authentication server (which may - * decide to reject the connection), - */ - wpa_auth_pmksa_remove(hapd->wpa_auth, addr); - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " - "for ESS disassociation imminent message", - MAC2STR(addr)); - return -1; - } - beacon_int = hapd->iconf->beacon_int; - if (beacon_int < 1) - beacon_int = 100; /* best guess */ - /* Calculate timeout in ms based on beacon_int in TU */ - timeout = disassoc_timer * beacon_int * 128 / 125; - wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR - " set to %d ms", MAC2STR(addr), timeout); - - sta->timeout_next = STA_DISASSOC_FROM_CLI; - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(timeout / 1000, - timeout % 1000 * 1000, - ap_handle_timer, hapd, sta); - } - - return 0; + return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); } #endif /* CONFIG_WNM */ @@ -994,6 +917,10 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) else hapd->gas_frag_limit = val; #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { + hapd->ext_mgmt_frame_handling = atoi(value); +#endif /* CONFIG_TESTING_OPTIONS */ } else { ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); } @@ -1051,6 +978,7 @@ static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) #ifdef CONFIG_TESTING_OPTIONS + static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) { union wpa_event_data data; @@ -1108,6 +1036,35 @@ static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) return 0; } + + +static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd) +{ + size_t len; + u8 *buf; + int res; + + wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(cmd, buf, len) < 0) { + os_free(buf); + return -1; + } + + res = hostapd_drv_send_mlme(hapd, buf, len, 0); + os_free(buf); + return res; +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -1127,6 +1084,19 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos) } +static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply, + int reply_size, const char *param) +{ +#ifdef RADIUS_SERVER + if (os_strcmp(param, "radius_server") == 0) { + return radius_server_get_mib(hapd->radius_srv, reply, + reply_size); + } +#endif /* RADIUS_SERVER */ + return -1; +} + + static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { @@ -1170,6 +1140,8 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strcmp(buf, "STATUS") == 0) { reply_len = hostapd_ctrl_iface_status(hapd, reply, reply_size); + } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) { + reply_len = hostapd_drv_status(hapd, reply, reply_size); } else if (os_strcmp(buf, "MIB") == 0) { reply_len = ieee802_11_get_mib(hapd, reply, reply_size); if (reply_len >= 0) { @@ -1199,6 +1171,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len += res; } #endif /* CONFIG_NO_RADIUS */ + } else if (os_strncmp(buf, "MIB ", 4) == 0) { + reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size, + buf + 4); } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, reply_size); @@ -1312,6 +1287,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "RADAR ", 6) == 0) { if (hostapd_ctrl_iface_radar(hapd, buf + 6)) reply_len = -1; + } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { + if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8)) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12)) diff --git a/hostapd/defconfig b/hostapd/defconfig index 3f2924b9..60f2c04e 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -96,10 +96,9 @@ CONFIG_EAP_TTLS=y #CONFIG_EAP_GPSK_SHA256=y # EAP-FAST for the integrated EAP server -# Note: Default OpenSSL package does not include support for all the -# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, -# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch) -# to add the needed functions. +# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed +# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g., +# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions. #CONFIG_EAP_FAST=y # Wi-Fi Protected Setup (WPS) @@ -180,7 +179,7 @@ CONFIG_IPV6=y # Note: This requires libnl 3.1 or newer. #CONFIG_VLAN_NETLINK=y -# Remove support for dumping state into a file on SIGUSR1 signal +# Remove support for dumping internal state through control interface commands # This can be used to reduce binary size at the cost of disabling a debugging # option. #CONFIG_NO_DUMP_STATE=y diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c deleted file mode 100644 index fcd98905..00000000 --- a/hostapd/dump_state.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * hostapd / State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" -#include <time.h> - -#include "utils/common.h" -#include "radius/radius_client.h" -#include "radius/radius_server.h" -#include "eapol_auth/eapol_auth_sm.h" -#include "eapol_auth/eapol_auth_sm_i.h" -#include "eap_server/eap.h" -#include "ap/hostapd.h" -#include "ap/ap_config.h" -#include "ap/sta_info.h" -#include "dump_state.h" -#include "ap/ap_drv_ops.h" - - -static void fprint_char(FILE *f, char c) -{ - if (c >= 32 && c < 127) - fprintf(f, "%c", c); - else - fprintf(f, "<%02x>", c); -} - - -static void ieee802_1x_dump_state(FILE *f, const char *prefix, - struct sta_info *sta) -{ - struct eapol_state_machine *sm = sta->eapol_sm; - if (sm == NULL) - return; - - fprintf(f, "%sIEEE 802.1X:\n", prefix); - - if (sm->identity) { - size_t i; - fprintf(f, "%sidentity=", prefix); - for (i = 0; i < sm->identity_len; i++) - fprint_char(f, sm->identity[i]); - fprintf(f, "\n"); - } - - fprintf(f, "%slast EAP type: Authentication Server: %d (%s) " - "Supplicant: %d (%s)\n", prefix, - sm->eap_type_authsrv, - eap_server_get_name(0, sm->eap_type_authsrv), - sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp)); - - fprintf(f, "%scached_packets=%s\n", prefix, - sm->last_recv_radius ? "[RX RADIUS]" : ""); - - eapol_auth_dump_state(f, prefix, sm); -} - - -/** - * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file - */ -static void hostapd_dump_state(struct hostapd_data *hapd) -{ - FILE *f; - time_t now; - struct sta_info *sta; - int i; -#ifndef CONFIG_NO_RADIUS - char *buf; -#endif /* CONFIG_NO_RADIUS */ - struct hostap_sta_driver_data data; - - if (!hapd->conf->dump_log_name) { - wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump " - "request"); - return; - } - - wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'", - hapd->conf->dump_log_name); - f = fopen(hapd->conf->dump_log_name, "w"); - if (f == NULL) { - wpa_printf(MSG_WARNING, "Could not open dump file '%s' for " - "writing.", hapd->conf->dump_log_name); - return; - } - - time(&now); - fprintf(f, "hostapd state dump - %s", ctime(&now)); - fprintf(f, "num_sta=%d num_sta_non_erp=%d " - "num_sta_no_short_slot_time=%d\n" - "num_sta_no_short_preamble=%d\n", - hapd->num_sta, hapd->iface->num_sta_non_erp, - hapd->iface->num_sta_no_short_slot_time, - hapd->iface->num_sta_no_short_preamble); - - for (sta = hapd->sta_list; sta != NULL; sta = sta->next) { - fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr)); - - fprintf(f, - " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "\n" - " capability=0x%x listen_interval=%d\n", - sta->aid, - sta->flags, - (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""), - (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), - (sta->flags & WLAN_STA_PS ? "[PS]" : ""), - (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""), - (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""), - (ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""), - (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : - ""), - (sta->flags & WLAN_STA_SHORT_PREAMBLE ? - "[SHORT_PREAMBLE]" : ""), - (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), - (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""), - (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""), - (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""), - (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), - (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""), - (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""), - (sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), - sta->capability, - sta->listen_interval); - - fprintf(f, " supported_rates="); - for (i = 0; i < sta->supported_rates_len; i++) - fprintf(f, "%02x ", sta->supported_rates[i]); - fprintf(f, "\n"); - - fprintf(f, - " timeout_next=%s\n", - (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" : - (sta->timeout_next == STA_DISASSOC ? "DISASSOC" : - "DEAUTH"))); - - ieee802_1x_dump_state(f, " ", sta); - - if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) == 0) { - fprintf(f, " rx_pkt=%lu tx_pkt=%lu\n" - " rx_byte=%lu tx_byte=%lu\n", - data.rx_packets, data.tx_packets, - data.rx_bytes, data.tx_bytes); - } - } - -#ifndef CONFIG_NO_RADIUS - buf = os_malloc(4096); - if (buf) { - int count = radius_client_get_mib(hapd->radius, buf, 4096); - if (count < 0) - count = 0; - else if (count > 4095) - count = 4095; - buf[count] = '\0'; - fprintf(f, "%s", buf); - -#ifdef RADIUS_SERVER - count = radius_server_get_mib(hapd->radius_srv, buf, 4096); - if (count < 0) - count = 0; - else if (count > 4095) - count = 4095; - buf[count] = '\0'; - fprintf(f, "%s", buf); -#endif /* RADIUS_SERVER */ - - os_free(buf); - } -#endif /* CONFIG_NO_RADIUS */ - fclose(f); -} - - -int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx) -{ - size_t i; - - for (i = 0; i < iface->num_bss; i++) - hostapd_dump_state(iface->bss[i]); - - return 0; -} diff --git a/hostapd/dump_state.h b/hostapd/dump_state.h deleted file mode 100644 index a209d653..00000000 --- a/hostapd/dump_state.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * hostapd / State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DUMP_STATE_H -#define DUMP_STATE_H - -int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx); - -#endif /* DUMP_STATE_H */ diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 9b70d0fb..da7817f4 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -51,9 +51,6 @@ logger_syslog_level=2 logger_stdout=-1 logger_stdout_level=2 -# Dump file for state information (on SIGUSR1) -dump_file=/tmp/hostapd.dump - # Interface for separate control program. If this is specified, hostapd # will create this directory and a UNIX domain socket for listening to requests # from external programs (CLI/GUI, etc.) for status information and diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index b2d3e5ba..eee85041 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1,6 +1,6 @@ /* * hostapd - command line interface for hostapd daemon - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,7 +18,7 @@ static const char *hostapd_cli_version = "hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors"; static const char *hostapd_cli_license = @@ -218,12 +218,19 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) { + if (argc > 0 && os_strcmp(argv[0], "driver") == 0) + return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); return wpa_ctrl_command(ctrl, "STATUS"); } static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) { + if (argc > 0) { + char buf[100]; + os_snprintf(buf, sizeof(buf), "MIB %s", argv[0]); + return wpa_ctrl_command(ctrl, buf); + } return wpa_ctrl_command(ctrl, "MIB"); } @@ -276,12 +283,15 @@ static void hostapd_cli_action_process(char *msg, size_t len) static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char buf[64]; - if (argc != 1) { - printf("Invalid 'sta' command - exactly one argument, STA " + if (argc < 1) { + printf("Invalid 'sta' command - at least one argument, STA " "address, is required.\n"); return -1; } - snprintf(buf, sizeof(buf), "STA %s", argv[0]); + if (argc > 1) + snprintf(buf, sizeof(buf), "STA %s %s", argv[0], argv[1]); + else + snprintf(buf, sizeof(buf), "STA %s", argv[0]); return wpa_ctrl_command(ctrl, buf); } diff --git a/hostapd/main.c b/hostapd/main.c index 4e9fe404..5a1b0a9e 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -25,17 +25,9 @@ #include "ap/ap_drv_ops.h" #include "config_file.h" #include "eap_register.h" -#include "dump_state.h" #include "ctrl_iface.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - -extern struct wpa_driver_ops *wpa_drivers[]; - - struct hapd_global { void **drv_priv; size_t drv_count; @@ -302,10 +294,7 @@ static void handle_reload(int sig, void *signal_ctx) static void handle_dump_state(int sig, void *signal_ctx) { -#ifdef HOSTAPD_DUMP_STATE - struct hapd_interfaces *interfaces = signal_ctx; - hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL); -#endif /* HOSTAPD_DUMP_STATE */ + /* Not used anymore - ignore signal */ } #endif /* CONFIG_NATIVE_WINDOWS */ @@ -424,7 +413,7 @@ static void show_version(void) "hostapd v" VERSION_STR "\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> " + "Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> " "and contributors\n"); } diff --git a/src/ap/accounting.c b/src/ap/accounting.c index a1f67f0c..6290d3f3 100644 --- a/src/ap/accounting.c +++ b/src/ap/accounting.c @@ -10,7 +10,6 @@ #include "utils/common.h" #include "utils/eloop.h" -#include "drivers/driver.h" #include "radius/radius.h" #include "radius/radius_client.h" #include "hostapd.h" @@ -202,7 +201,6 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx) void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) { struct radius_msg *msg; - struct os_time t; int interval; if (sta->acct_session_started) @@ -213,8 +211,7 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) "starting accounting session %08X-%08X", sta->acct_session_id_hi, sta->acct_session_id_lo); - os_get_time(&t); - sta->acct_session_start = t.sec; + os_get_reltime(&sta->acct_session_start); sta->last_rx_bytes = sta->last_tx_bytes = 0; sta->acct_input_gigawords = sta->acct_output_gigawords = 0; hostapd_drv_sta_clear_stats(hapd, sta->addr); @@ -244,6 +241,7 @@ static void accounting_sta_report(struct hostapd_data *hapd, struct radius_msg *msg; int cause = sta->acct_terminate_cause; struct hostap_sta_driver_data data; + struct os_reltime now_r, diff; struct os_time now; u32 gigawords; @@ -258,9 +256,11 @@ static void accounting_sta_report(struct hostapd_data *hapd, return; } + os_get_reltime(&now_r); os_get_time(&now); + os_reltime_sub(&now_r, &sta->acct_session_start, &diff); if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME, - now.sec - sta->acct_session_start)) { + diff.sec)) { wpa_printf(MSG_INFO, "Could not add Acct-Session-Time"); goto fail; } diff --git a/src/ap/acs.c b/src/ap/acs.c index 9ef221ed..f58b091e 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -280,7 +280,7 @@ static void acs_cleanup(struct hostapd_iface *iface) } -void acs_fail(struct hostapd_iface *iface) +static void acs_fail(struct hostapd_iface *iface) { wpa_printf(MSG_ERROR, "ACS: Failed to start"); acs_cleanup(iface); diff --git a/src/ap/acs.h b/src/ap/acs.h index a41f17f3..fc85259e 100644 --- a/src/ap/acs.h +++ b/src/ap/acs.h @@ -13,7 +13,6 @@ #ifdef CONFIG_ACS enum hostapd_chan_status acs_init(struct hostapd_iface *iface); -int hostapd_acs_completed(struct hostapd_iface *iface, int err); #else /* CONFIG_ACS */ diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 65a6f12a..a29f4d0e 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -433,7 +433,6 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) } os_free(conf->eap_user_sqlite); - os_free(conf->dump_log_name); os_free(conf->eap_req_id_text); os_free(conf->accept_mac); os_free(conf->deny_mac); @@ -759,7 +758,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, if (conf->ieee80211n && bss->wpa && !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) { + !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) + { bss->disable_11n = 1; wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 " "requires CCMP/GCMP to be enabled, disabling HT " @@ -792,7 +793,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, #ifdef CONFIG_HS20 if (bss->hs20 && (!(bss->wpa & 2) || - !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) { + !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_CCMP_256 | + WPA_CIPHER_GCMP_256)))) { wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP " "configuration is required for Hotspot 2.0 " "functionality"); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 09b2778e..af30ac49 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -189,8 +189,6 @@ struct hostapd_bss_config { unsigned int logger_syslog; /* module bitfield */ unsigned int logger_stdout; /* module bitfield */ - char *dump_log_name; /* file name for state dump (SIGUSR1) */ - int max_num_sta; /* maximum number of STAs in station table */ int dtim_period; diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 09b5f68b..893e6d9e 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -9,7 +9,6 @@ #include "utils/includes.h" #include "utils/common.h" -#include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "wps/wps.h" #include "p2p/p2p.h" @@ -715,7 +714,7 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper, const u8 *peer, u8 *buf, u16 *buf_len) { if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL) - return 0; + return -1; return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf, buf_len); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index b5f6a020..15a4b267 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -1,6 +1,6 @@ /* * hostapd - Driver operations - * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -272,4 +272,12 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd, return hapd->driver->switch_channel(hapd->drv_priv, settings); } +static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, + size_t buflen) +{ + if (hapd->driver == NULL || hapd->driver->status == NULL) + return -1; + return hapd->driver->status(hapd->drv_priv, buf, buflen); +} + #endif /* AP_DRV_OPS */ diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c index 0dab39fa..f9b15401 100644 --- a/src/ap/ap_list.c +++ b/src/ap/ap_list.c @@ -14,7 +14,6 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "ieee802_11.h" diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 0e0dae46..5318ecb7 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -4,14 +4,8 @@ * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -21,7 +15,6 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" -#include "drivers/driver.h" #include "wps/wps_defs.h" #include "p2p/p2p.h" #include "hostapd.h" @@ -207,10 +200,10 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) { u8 chan; - if (!hapd->iface->cs_freq) + if (!hapd->iface->cs_freq_params.freq) return eid; - if (ieee80211_freq_to_chan(hapd->iface->cs_freq, &chan) == + if (ieee80211_freq_to_chan(hapd->iface->cs_freq_params.freq, &chan) == NUM_HOSTAPD_MODES) return eid; @@ -224,13 +217,56 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) } +static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) +{ + u8 sec_ch; + + if (!hapd->iface->cs_freq_params.sec_channel_offset) + return eid; + + if (hapd->iface->cs_freq_params.sec_channel_offset == -1) + sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; + else if (hapd->iface->cs_freq_params.sec_channel_offset == 1) + sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; + else + return eid; + + *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; + *eid++ = 1; + *eid++ = sec_ch; + + return eid; +} + + +static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos, + u8 *start, unsigned int *csa_counter_off) +{ + u8 *old_pos = pos; + + if (!csa_counter_off) + return pos; + + *csa_counter_off = 0; + pos = hostapd_eid_csa(hapd, pos); + + if (pos != old_pos) { + /* save an offset to the counter - should be last byte */ + *csa_counter_off = pos - start - 1; + pos = hostapd_eid_secondary_channel(hapd, pos); + } + + return pos; +} + + static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *req, int is_p2p, size_t *resp_len) { struct ieee80211_mgmt *resp; - u8 *pos, *epos, *old_pos; + u8 *pos, *epos; size_t buflen; #define MAX_PROBERESP_LEN 768 @@ -304,13 +340,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_adv_proto(hapd, pos); pos = hostapd_eid_roaming_consortium(hapd, pos); - old_pos = pos; - pos = hostapd_eid_csa(hapd, pos); - - /* save an offset to the counter - should be last byte */ - hapd->iface->cs_c_off_proberesp = (pos != old_pos) ? - pos - (u8 *) resp - 1 : 0; - + pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, + &hapd->iface->cs_c_off_proberesp); #ifdef CONFIG_IEEE80211AC pos = hostapd_eid_vht_capabilities(hapd, pos); pos = hostapd_eid_vht_operation(hapd, pos); @@ -626,7 +657,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, size_t resp_len = 0; #ifdef NEED_AP_MLME u16 capab_info; - u8 *pos, *tailpos, *old_pos; + u8 *pos, *tailpos; #define BEACON_HEAD_BUF_SIZE 256 #define BEACON_TAIL_BUF_SIZE 512 @@ -721,11 +752,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_interworking(hapd, tailpos); tailpos = hostapd_eid_adv_proto(hapd, tailpos); tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); - old_pos = tailpos; - tailpos = hostapd_eid_csa(hapd, tailpos); - hapd->iface->cs_c_off_beacon = (old_pos != tailpos) ? - tailpos - tail - 1 : 0; - + tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, + &hapd->iface->cs_c_off_beacon); #ifdef CONFIG_IEEE80211AC tailpos = hostapd_eid_vht_capabilities(hapd, tailpos); tailpos = hostapd_eid_vht_operation(hapd, tailpos); @@ -844,20 +872,21 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) } -void ieee802_11_set_beacon(struct hostapd_data *hapd) +int ieee802_11_set_beacon(struct hostapd_data *hapd) { struct wpa_driver_ap_params params; struct wpabuf *beacon, *proberesp, *assocresp; + int res, ret = -1; if (hapd->iface->csa_in_progress) { wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period"); - return; + return -1; } hapd->beacon_set_done = 1; if (ieee802_11_build_ap_params(hapd, ¶ms) < 0) - return; + return -1; if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < 0) @@ -867,31 +896,46 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) params.proberesp_ies = proberesp; params.assocresp_ies = assocresp; - if (hostapd_drv_set_ap(hapd, ¶ms)) - wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); + res = hostapd_drv_set_ap(hapd, ¶ms); hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); + if (res) + wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); + else + ret = 0; fail: ieee802_11_free_ap_params(¶ms); + return ret; } -void ieee802_11_set_beacons(struct hostapd_iface *iface) +int ieee802_11_set_beacons(struct hostapd_iface *iface) { size_t i; + int ret = 0; + for (i = 0; i < iface->num_bss; i++) { - if (iface->bss[i]->started) - ieee802_11_set_beacon(iface->bss[i]); + if (iface->bss[i]->started && + ieee802_11_set_beacon(iface->bss[i]) < 0) + ret = -1; } + + return ret; } /* only update beacons if started */ -void ieee802_11_update_beacons(struct hostapd_iface *iface) +int ieee802_11_update_beacons(struct hostapd_iface *iface) { size_t i; - for (i = 0; i < iface->num_bss; i++) - if (iface->bss[i]->beacon_set_done && iface->bss[i]->started) - ieee802_11_set_beacon(iface->bss[i]); + int ret = 0; + + for (i = 0; i < iface->num_bss; i++) { + if (iface->bss[i]->beacon_set_done && iface->bss[i]->started && + ieee802_11_set_beacon(iface->bss[i]) < 0) + ret = -1; + } + + return ret; } #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/src/ap/beacon.h b/src/ap/beacon.h index a04a829c..722159a7 100644 --- a/src/ap/beacon.h +++ b/src/ap/beacon.h @@ -3,14 +3,8 @@ * Copyright (c) 2002-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef BEACON_H @@ -21,9 +15,9 @@ struct ieee80211_mgmt; void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ssi_signal); -void ieee802_11_set_beacon(struct hostapd_data *hapd); -void ieee802_11_set_beacons(struct hostapd_iface *iface); -void ieee802_11_update_beacons(struct hostapd_iface *iface); +int ieee802_11_set_beacon(struct hostapd_data *hapd); +int ieee802_11_set_beacons(struct hostapd_iface *iface); +int ieee802_11_update_beacons(struct hostapd_iface *iface); int ieee802_11_build_ap_params(struct hostapd_data *hapd, struct wpa_driver_ap_params *params); void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params); diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 4125fd56..3fb9e04b 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -10,6 +10,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "eapol_auth/eapol_auth_sm.h" #include "hostapd.h" #include "ieee802_1x.h" #include "wpa_auth.h" @@ -21,24 +22,61 @@ #include "ap_drv_ops.h" +static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd, + struct sta_info *sta, + char *buf, size_t buflen) +{ + struct hostap_sta_driver_data data; + int ret; + + if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) + return 0; + + ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n" + "rx_bytes=%lu\ntx_bytes=%lu\n", + data.rx_packets, data.tx_packets, + data.rx_bytes, data.tx_bytes); + if (ret < 0 || (size_t) ret >= buflen) + return 0; + return ret; +} + + static int hostapd_get_sta_conn_time(struct sta_info *sta, char *buf, size_t buflen) { struct os_reltime age; - int len = 0, ret; + int ret; if (!sta->connected_time.sec) return 0; os_reltime_age(&sta->connected_time, &age); - ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n", + ret = os_snprintf(buf, buflen, "connected_time=%u\n", (unsigned int) age.sec); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; + if (ret < 0 || (size_t) ret >= buflen) + return 0; + return ret; +} - return len; + +static const char * timeout_next_str(int val) +{ + switch (val) { + case STA_NULLFUNC: + return "NULLFUNC POLL"; + case STA_DISASSOC: + return "DISASSOC"; + case STA_DEAUTH: + return "DEAUTH"; + case STA_REMOVE: + return "REMOVE"; + case STA_DISASSOC_FROM_CLI: + return "DISASSOC_FROM_CLI"; + } + + return "?"; } @@ -46,22 +84,42 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, struct sta_info *sta, char *buf, size_t buflen) { - int len, res, ret; - - if (sta == NULL) { - ret = os_snprintf(buf, buflen, "FAIL\n"); - if (ret < 0 || (size_t) ret >= buflen) - return 0; - return ret; - } + int len, res, ret, i; len = 0; - ret = os_snprintf(buf + len, buflen - len, MACSTR "\n", + ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=", MAC2STR(sta->addr)); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; + ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len); + if (ret < 0) + return len; + len += ret; + + ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n" + "listen_interval=%d\nsupported_rates=", + sta->aid, sta->capability, sta->listen_interval); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + + for (i = 0; i < sta->supported_rates_len; i++) { + ret = os_snprintf(buf + len, buflen - len, "%02x%s", + sta->supported_rates[i], + i + 1 < sta->supported_rates_len ? " " : ""); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + } + + ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n", + timeout_next_str(sta->timeout_next)); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); if (res >= 0) len += res; @@ -79,9 +137,8 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, if (res >= 0) len += res; - res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len); - if (res >= 0) - len += res; + len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len); + len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len); return len; } @@ -99,6 +156,8 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, { u8 addr[ETH_ALEN]; int ret; + const char *pos; + struct sta_info *sta; if (hwaddr_aton(txtaddr, addr)) { ret = os_snprintf(buf, buflen, "FAIL\n"); @@ -106,8 +165,28 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, return 0; return ret; } - return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr), - buf, buflen); + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) + return -1; + + pos = os_strchr(txtaddr, ' '); + if (pos) { + pos++; + +#ifdef HOSTAPD_DUMP_STATE + if (os_strcmp(pos, "eapol") == 0) { + if (sta->eapol_sm == NULL) + return -1; + return eapol_auth_dump_state(sta->eapol_sm, buf, + buflen); + } +#endif /* HOSTAPD_DUMP_STATE */ + + return -1; + } + + return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen); } diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index b066bffd..9af96468 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -299,6 +299,7 @@ skip_wpa_check: new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); @@ -439,7 +440,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; - if (hapd->iface->csa_in_progress && freq == hapd->iface->cs_freq) { + if (hapd->iface->csa_in_progress && + freq == hapd->iface->cs_freq_params.freq) { hostapd_cleanup_cs_params(hapd); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d", @@ -556,39 +558,48 @@ fail: static void hostapd_action_rx(struct hostapd_data *hapd, - struct rx_action *action) + struct rx_mgmt *drv_mgmt) { + struct ieee80211_mgmt *mgmt; struct sta_info *sta; + size_t plen __maybe_unused; + u16 fc; + + if (drv_mgmt->frame_len < 24 + 1) + return; + + plen = drv_mgmt->frame_len - 24 - 1; + + mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; + fc = le_to_host16(mgmt->frame_control); + if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) + return; /* handled by the driver */ wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", - action->category, (int) action->len); + mgmt->u.action.category, (int) plen); - sta = ap_get_sta(hapd, action->sa); + sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { wpa_printf(MSG_DEBUG, "%s: station not found", __func__); return; } #ifdef CONFIG_IEEE80211R - if (action->category == WLAN_ACTION_FT) { - wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d", - __func__, (int) action->len); - wpa_ft_action_rx(sta->wpa_sm, action->data, action->len); + if (mgmt->u.action.category == WLAN_ACTION_FT) { + const u8 *payload = drv_mgmt->frame + 24 + 1; + wpa_ft_action_rx(sta->wpa_sm, payload, plen); } #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W - if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) { - wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d", - __func__, (int) action->len); - ieee802_11_sa_query_action(hapd, action->sa, - *(action->data + 1), - action->data + 2); + if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) { + ieee802_11_sa_query_action( + hapd, mgmt->sa, + mgmt->u.action.u.sa_query_resp.action, + mgmt->u.action.u.sa_query_resp.trans_id); } #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WNM - if (action->category == WLAN_ACTION_WNM) { - wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d", - __func__, (int) action->len); - ieee802_11_rx_wnm_action_ap(hapd, action); + if (mgmt->u.action.category == WLAN_ACTION_WNM) { + ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); } #endif /* CONFIG_WNM */ } @@ -630,17 +641,18 @@ static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, } -static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) +static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) { struct hostapd_iface *iface = hapd->iface; const struct ieee80211_hdr *hdr; const u8 *bssid; struct hostapd_frame_info fi; + int ret; hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); if (bssid == NULL) - return; + return 0; hapd = get_hapd_bssid(iface, bssid); if (hapd == NULL) { @@ -655,7 +667,7 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) hapd = iface->bss[0]; else - return; + return 0; } os_memset(&fi, 0, sizeof(fi)); @@ -664,53 +676,19 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) if (hapd == HAPD_BROADCAST) { size_t i; - for (i = 0; i < iface->num_bss; i++) - ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, - rx_mgmt->frame_len, &fi); + ret = 0; + for (i = 0; i < iface->num_bss; i++) { + if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, + rx_mgmt->frame_len, &fi) > 0) + ret = 1; + } } else - ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi); + ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, + &fi); random_add_randomness(&fi, sizeof(fi)); -} - -static void hostapd_rx_action(struct hostapd_data *hapd, - struct rx_action *rx_action) -{ - struct rx_mgmt rx_mgmt; - u8 *buf; - struct ieee80211_hdr *hdr; - - wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR - " BSSID=" MACSTR " category=%u", - MAC2STR(rx_action->da), MAC2STR(rx_action->sa), - MAC2STR(rx_action->bssid), rx_action->category); - wpa_hexdump(MSG_MSGDUMP, "Received action frame contents", - rx_action->data, rx_action->len); - - buf = os_zalloc(24 + 1 + rx_action->len); - if (buf == NULL) - return; - hdr = (struct ieee80211_hdr *) buf; - hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - if (rx_action->category == WLAN_ACTION_SA_QUERY) { - /* - * Assume frame was protected; it would have been dropped if - * not. - */ - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); - } - os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN); - os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN); - os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN); - buf[24] = rx_action->category; - os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len); - os_memset(&rx_mgmt, 0, sizeof(rx_mgmt)); - rx_mgmt.frame = buf; - rx_mgmt.frame_len = 24 + 1 + rx_action->len; - hostapd_mgmt_rx(hapd, &rx_mgmt); - os_free(buf); + return ret; } @@ -952,10 +930,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_from_unknown.addr, data->rx_from_unknown.wds); break; +#endif /* NEED_AP_MLME */ case EVENT_RX_MGMT: - hostapd_mgmt_rx(hapd, &data->rx_mgmt); - break; +#ifdef NEED_AP_MLME + if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0) + break; #endif /* NEED_AP_MLME */ + hostapd_action_rx(hapd, &data->rx_mgmt); + break; case EVENT_RX_PROBE_REQ: if (data->rx_probe_req.sa == NULL || data->rx_probe_req.ie == NULL) @@ -994,15 +976,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; hostapd_event_sta_low_ack(hapd, data->low_ack.addr); break; - case EVENT_RX_ACTION: - if (data->rx_action.da == NULL || data->rx_action.sa == NULL || - data->rx_action.bssid == NULL) - break; -#ifdef NEED_AP_MLME - hostapd_rx_action(hapd, &data->rx_action); -#endif /* NEED_AP_MLME */ - hostapd_action_rx(hapd, &data->rx_action); - break; case EVENT_AUTH: hostapd_notif_auth(hapd, &data->auth); break; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a436c2ae..44d05c5d 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -14,7 +14,6 @@ #include "common/wpa_ctrl.h" #include "radius/radius_client.h" #include "radius/radius_das.h" -#include "drivers/driver.h" #include "hostapd.h" #include "authsrv.h" #include "sta_info.h" @@ -42,9 +41,6 @@ static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd); static int setup_interface2(struct hostapd_iface *iface); static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); -extern int wpa_debug_level; -extern struct wpa_driver_ops *wpa_drivers[]; - int hostapd_for_each_interface(struct hapd_interfaces *interfaces, int (*cb)(struct hostapd_iface *iface, @@ -811,8 +807,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (!hapd->conf->start_disabled) - ieee802_11_set_beacon(hapd); + if (!hapd->conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) + return -1; if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) return -1; @@ -2200,7 +2196,7 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, return ret; /* set channel switch parameters for csa ie */ - iface->cs_freq = settings->freq_params.freq; + iface->cs_freq_params = settings->freq_params; iface->cs_count = settings->cs_count; iface->cs_block_tx = settings->block_tx; @@ -2219,7 +2215,8 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, void hostapd_cleanup_cs_params(struct hostapd_data *hapd) { - hapd->iface->cs_freq = 0; + os_memset(&hapd->iface->cs_freq_params, 0, + sizeof(hapd->iface->cs_freq_params)); hapd->iface->cs_count = 0; hapd->iface->cs_block_tx = 0; hapd->iface->cs_c_off_beacon = 0; diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 84468de0..489ab165 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -11,14 +11,13 @@ #include "common/defs.h" #include "ap_config.h" +#include "drivers/driver.h" -struct wpa_driver_ops; struct wpa_ctrl_dst; struct radius_server_data; struct upnp_wps_device_sm; struct hostapd_data; struct sta_info; -struct hostap_sta_driver_data; struct ieee80211_ht_capabilities; struct full_dynamic_vlan; enum wps_event; @@ -27,8 +26,6 @@ union wps_event_data; struct hostapd_iface; struct hostapd_dynamic_iface; -struct csa_settings; - struct hapd_interfaces { int (*reload_config)(struct hostapd_iface *iface); struct hostapd_config * (*config_read_cb)(const char *config_fname); @@ -146,7 +143,7 @@ struct hostapd_data { struct eapol_authenticator *eapol_auth; struct rsn_preauth_interface *preauth_iface; - time_t michael_mic_failure; + struct os_reltime michael_mic_failure; int michael_mic_failures; int tkip_countermeasures; @@ -243,6 +240,10 @@ struct hostapd_data { u8 sae_token_key[8]; struct os_reltime last_sae_token_key_update; #endif /* CONFIG_SAE */ + +#ifdef CONFIG_TESTING_OPTIONS + int ext_mgmt_frame_handling; +#endif /* CONFIG_TESTING_OPTIONS */ }; @@ -337,7 +338,7 @@ struct hostapd_iface { s8 lowest_nf; /* channel switch parameters */ - int cs_freq; + struct hostapd_freq_params cs_freq_params; u8 cs_count; int cs_block_tx; unsigned int cs_c_off_beacon; diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index e95e0e1a..4e663795 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -21,7 +15,6 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "ap_drv_ops.h" diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index abadcd13..783ae5e1 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef HW_FEATURES_H @@ -21,6 +15,7 @@ void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, size_t num_hw_features); int hostapd_get_hw_features(struct hostapd_iface *iface); +int hostapd_acs_completed(struct hostapd_iface *iface, int err); int hostapd_select_hw_mode(struct hostapd_iface *iface); const char * hostapd_hw_mode_txt(int mode); int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan); diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index e55f843c..1e3693d1 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -15,7 +15,6 @@ #include "crypto/crypto.h" #include "crypto/sha256.h" #include "crypto/random.h" -#include "drivers/driver.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" @@ -239,13 +238,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (shared key)"); -#ifdef IEEE80211_REQUIRE_AUTH_ACK - /* Station will be marked authenticated if it ACKs the - * authentication reply. */ -#else sta->flags |= WLAN_STA_AUTH; wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); -#endif os_free(sta->challenge); sta->challenge = NULL; @@ -691,15 +685,10 @@ static void handle_auth(struct hostapd_data *hapd, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (open system)"); -#ifdef IEEE80211_REQUIRE_AUTH_ACK - /* Station will be marked authenticated if it ACKs the - * authentication reply. */ -#else sta->flags |= WLAN_STA_AUTH; wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); sta->auth_alg = WLAN_AUTH_OPEN; mlme_authenticate_indication(hapd, sta); -#endif break; case WLAN_AUTH_SHARED_KEY: resp = auth_shared_key(hapd, sta, auth_transaction, challenge, @@ -926,7 +915,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "Station does not support " "mandatory VHT PHY - reject association"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + return WLAN_STATUS_ASSOC_DENIED_NO_VHT; } #endif /* CONFIG_IEEE80211AC */ @@ -1068,7 +1057,9 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_SAE if (wpa_auth_uses_sae(sta->wpa_sm) && - sta->auth_alg != WLAN_AUTH_SAE) { + sta->auth_alg != WLAN_AUTH_SAE && + !(sta->auth_alg == WLAN_AUTH_FT && + wpa_auth_uses_ft_sae(sta->wpa_sm))) { wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use " "SAE AKM after non-SAE auth_alg %u", MAC2STR(sta->addr), sta->auth_alg); @@ -1544,9 +1535,9 @@ static void handle_beacon(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211W -static void hostapd_sa_query_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, - size_t len) +static int hostapd_sa_query_action(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len) { const u8 *end; @@ -1555,12 +1546,13 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, if (((u8 *) mgmt) + len < end) { wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action " "frame (len=%lu)", (unsigned long) len); - return; + return 0; } ieee802_11_sa_query_action(hapd, mgmt->sa, mgmt->u.action.u.sa_query_resp.action, mgmt->u.action.u.sa_query_resp.trans_id); + return 1; } @@ -1572,29 +1564,8 @@ static int robust_action_frame(u8 category) #endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WNM -static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta, - const struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct rx_action action; - if (len < IEEE80211_HDRLEN + 2) - return; - os_memset(&action, 0, sizeof(action)); - action.da = mgmt->da; - action.sa = mgmt->sa; - action.bssid = mgmt->bssid; - action.category = mgmt->u.action.category; - action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action; - action.len = len - IEEE80211_HDRLEN - 1; - action.freq = hapd->iface->freq; - ieee802_11_rx_wnm_action_ap(hapd, &action); -} -#endif /* CONFIG_WNM */ - - -static void handle_action(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) +static int handle_action(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; sta = ap_get_sta(hapd, mgmt->sa); @@ -1604,7 +1575,7 @@ static void handle_action(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "handle_action - too short payload (len=%lu)", (unsigned long) len); - return; + return 0; } if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && @@ -1612,7 +1583,7 @@ static void handle_action(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action " "frame (category=%u) from unassociated STA " MACSTR, MAC2STR(mgmt->sa), mgmt->u.action.category); - return; + return 0; } #ifdef CONFIG_IEEE80211W @@ -1623,7 +1594,7 @@ static void handle_action(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "Dropped unprotected Robust Action frame from " "an MFP STA"); - return; + return 0; } #endif /* CONFIG_IEEE80211W */ @@ -1633,20 +1604,19 @@ static void handle_action(struct hostapd_data *hapd, if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, len - IEEE80211_HDRLEN)) break; - return; + return 1; #endif /* CONFIG_IEEE80211R */ case WLAN_ACTION_WMM: hostapd_wmm_action(hapd, mgmt, len); - return; + return 1; #ifdef CONFIG_IEEE80211W case WLAN_ACTION_SA_QUERY: - hostapd_sa_query_action(hapd, mgmt, len); - return; + return hostapd_sa_query_action(hapd, mgmt, len); #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WNM case WLAN_ACTION_WNM: - hostapd_wnm_action(hapd, sta, mgmt, len); - return; + ieee802_11_rx_wnm_action_ap(hapd, mgmt, len); + return 1; #endif /* CONFIG_WNM */ case WLAN_ACTION_PUBLIC: if (hapd->public_action_cb) { @@ -1660,14 +1630,14 @@ static void handle_action(struct hostapd_data *hapd, hapd->iface->freq); } if (hapd->public_action_cb || hapd->public_action_cb2) - return; + return 1; break; case WLAN_ACTION_VENDOR_SPECIFIC: if (hapd->vendor_action_cb) { if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, (u8 *) mgmt, len, hapd->iface->freq) == 0) - return; + return 1; } break; } @@ -1690,7 +1660,7 @@ static void handle_action(struct hostapd_data *hapd, "frame back to sender"); resp = os_malloc(len); if (resp == NULL) - return; + return 0; os_memcpy(resp, mgmt, len); os_memcpy(resp->da, resp->sa, ETH_ALEN); os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); @@ -1703,6 +1673,8 @@ static void handle_action(struct hostapd_data *hapd, } os_free(resp); } + + return 1; } @@ -1719,15 +1691,29 @@ static void handle_action(struct hostapd_data *hapd, * addition, it can be called to re-inserted pending frames (e.g., when using * external RADIUS server as an MAC ACL). */ -void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, - struct hostapd_frame_info *fi) +int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, + struct hostapd_frame_info *fi) { struct ieee80211_mgmt *mgmt; int broadcast; u16 fc, stype; + int ret = 0; + +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->ext_mgmt_frame_handling) { + size_t hex_len = 2 * len + 1; + char *hex = os_malloc(hex_len); + if (hex) { + wpa_snprintf_hex(hex, hex_len, buf, len); + wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); + os_free(hex); + } + return 1; + } +#endif /* CONFIG_TESTING_OPTIONS */ if (len < 24) - return; + return 0; mgmt = (struct ieee80211_mgmt *) buf; fc = le_to_host16(mgmt->frame_control); @@ -1735,7 +1721,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, if (stype == WLAN_FC_STYPE_BEACON) { handle_beacon(hapd, mgmt, len, fi); - return; + return 1; } broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff && @@ -1751,13 +1737,13 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address", MAC2STR(mgmt->bssid)); - return; + return 0; } if (stype == WLAN_FC_STYPE_PROBE_REQ) { handle_probe_req(hapd, mgmt, len, fi->ssi_signal); - return; + return 1; } if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { @@ -1765,33 +1751,38 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, HOSTAPD_LEVEL_DEBUG, "MGMT: DA=" MACSTR " not our address", MAC2STR(mgmt->da)); - return; + return 0; } switch (stype) { case WLAN_FC_STYPE_AUTH: wpa_printf(MSG_DEBUG, "mgmt::auth"); handle_auth(hapd, mgmt, len); + ret = 1; break; case WLAN_FC_STYPE_ASSOC_REQ: wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); handle_assoc(hapd, mgmt, len, 0); + ret = 1; break; case WLAN_FC_STYPE_REASSOC_REQ: wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); handle_assoc(hapd, mgmt, len, 1); + ret = 1; break; case WLAN_FC_STYPE_DISASSOC: wpa_printf(MSG_DEBUG, "mgmt::disassoc"); handle_disassoc(hapd, mgmt, len); + ret = 1; break; case WLAN_FC_STYPE_DEAUTH: wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); handle_deauth(hapd, mgmt, len); + ret = 1; break; case WLAN_FC_STYPE_ACTION: wpa_printf(MSG_DEBUG, "mgmt::action"); - handle_action(hapd, mgmt, len); + ret = handle_action(hapd, mgmt, len); break; default: hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1799,6 +1790,8 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, "unknown mgmt frame subtype %d", stype); break; } + + return ret; } @@ -1919,6 +1912,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, if (sta->flags & WLAN_STA_ASSOC) new_assoc = 0; sta->flags |= WLAN_STA_ASSOC; + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || sta->auth_alg == WLAN_AUTH_FT) { /* @@ -2075,6 +2069,14 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, const struct ieee80211_mgmt *mgmt; mgmt = (const struct ieee80211_mgmt *) buf; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->ext_mgmt_frame_handling) { + wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-TX-STATUS stype=%u ok=%d", + stype, ok); + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ + switch (stype) { case WLAN_FC_STYPE_AUTH: wpa_printf(MSG_DEBUG, "mgmt::auth cb"); diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 61f13167..5edeb71c 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -15,8 +15,8 @@ struct sta_info; struct hostapd_frame_info; struct ieee80211_ht_capabilities; -void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, - struct hostapd_frame_info *fi); +int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, + struct hostapd_frame_info *fi); void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, u16 stype, int ok); void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len); diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 2d53648c..31dc47ed 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -3,21 +3,14 @@ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2007-2008, Intel Corporation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" #include "utils/common.h" #include "common/ieee802_11_defs.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "sta_info.h" diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c index 60e6b572..f2ab182d 100644 --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -12,7 +12,6 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ap_config.h" #include "sta_info.h" diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 4465d12e..49b30e41 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -29,6 +29,7 @@ #include "pmksa_cache_auth.h" #include "ap_config.h" #include "ap_drv_ops.h" +#include "wps_hostapd.h" #include "ieee802_1x.h" @@ -1951,7 +1952,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, { int len = 0, ret; struct eapol_state_machine *sm = sta->eapol_sm; - struct os_time t; + struct os_reltime diff; if (sm == NULL) return 0; @@ -2066,7 +2067,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, len += ret; /* dot1xAuthSessionStatsTable */ - os_get_time(&t); + os_reltime_age(&sta->acct_session_start, &diff); ret = os_snprintf(buf + len, buflen - len, /* TODO: dot1xAuthSessionOctetsRx */ /* TODO: dot1xAuthSessionOctetsTx */ @@ -2081,12 +2082,23 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, (wpa_key_mgmt_wpa_ieee8021x( wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 1 : 2, - (unsigned int) (t.sec - sta->acct_session_start), + (unsigned int) diff.sec, sm->identity); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; + ret = os_snprintf(buf + len, buflen - len, + "last_eap_type_as=%d (%s)\n" + "last_eap_type_sta=%d (%s)\n", + sm->eap_type_authsrv, + eap_server_get_name(0, sm->eap_type_authsrv), + sm->eap_type_supp, + eap_server_get_name(0, sm->eap_type_supp)); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + return len; } @@ -2128,5 +2140,6 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, os_sleep(0, 10000); ap_sta_disconnect(hapd, sta, sta->addr, WLAN_REASON_IEEE_802_1X_AUTH_FAILED); + hostapd_wps_eap_completed(hapd); } } diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c index 40972e9a..4720b59c 100644 --- a/src/ap/pmksa_cache_auth.c +++ b/src/ap/pmksa_cache_auth.c @@ -91,9 +91,9 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) { struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " MACSTR, MAC2STR(pmksa->pmksa->spa)); @@ -107,12 +107,12 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) { int sec; - struct os_time now; + struct os_reltime now; eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); if (pmksa->pmksa == NULL) return; - os_get_time(&now); + os_get_reltime(&now); sec = pmksa->pmksa->expiration - now.sec; if (sec < 0) sec = 0; @@ -241,7 +241,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, struct eapol_state_machine *eapol, int akmp) { struct rsn_pmksa_cache_entry *entry, *pos; - struct os_time now; + struct os_reltime now; if (pmk_len > PMK_LEN) return NULL; @@ -253,7 +253,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, entry->pmk_len = pmk_len; rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, wpa_key_mgmt_sha256(akmp)); - os_get_time(&now); + os_get_reltime(&now); entry->expiration = now.sec; if (session_timeout > 0) entry->expiration += session_timeout; diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index d1d86571..670b8344 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -15,7 +15,6 @@ #include "common/sae.h" #include "radius/radius.h" #include "radius/radius_client.h" -#include "drivers/driver.h" #include "p2p/p2p.h" #include "hostapd.h" #include "accounting.h" @@ -495,7 +494,7 @@ void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, u32 session_timeout) { if (eloop_replenish_timeout(session_timeout, 0, - ap_handle_session_timer, hapd, sta)) { + ap_handle_session_timer, hapd, sta) == 1) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "setting session timeout " "to %d seconds", session_timeout); @@ -1012,3 +1011,33 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); ap_sta_disassoc_cb_timeout(hapd, sta); } + + +int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) +{ + int res; + + buf[0] = '\0'; + res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), + (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), + (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), + (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : + ""), + (flags & WLAN_STA_SHORT_PREAMBLE ? + "[SHORT_PREAMBLE]" : ""), + (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), + (flags & WLAN_STA_WMM ? "[WMM]" : ""), + (flags & WLAN_STA_MFP ? "[MFP]" : ""), + (flags & WLAN_STA_WPS ? "[WPS]" : ""), + (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), + (flags & WLAN_STA_WDS ? "[WDS]" : ""), + (flags & WLAN_STA_NONERP ? "[NonERP]" : ""), + (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), + (flags & WLAN_STA_GAS ? "[GAS]" : ""), + (flags & WLAN_STA_VHT ? "[VHT]" : ""), + (flags & WLAN_STA_WNM_SLEEP_MODE ? + "[WNM_SLEEP_MODE]" : "")); + + return res; +} diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index ea3fe407..9b77e060 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -12,9 +12,6 @@ /* STA flags */ #define WLAN_STA_AUTH BIT(0) #define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) -#define WLAN_STA_PERM BIT(4) #define WLAN_STA_AUTHORIZED BIT(5) #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ #define WLAN_STA_SHORT_PREAMBLE BIT(7) @@ -29,6 +26,7 @@ #define WLAN_STA_WPS2 BIT(16) #define WLAN_STA_GAS BIT(17) #define WLAN_STA_VHT BIT(18) +#define WLAN_STA_WNM_SLEEP_MODE BIT(19) #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) @@ -78,7 +76,7 @@ struct sta_info { u32 acct_session_id_hi; u32 acct_session_id_lo; - time_t acct_session_start; + struct os_reltime acct_session_start; int acct_session_started; int acct_terminate_cause; /* Acct-Terminate-Cause */ int acct_interim_interval; /* Acct-Interim-Interval */ @@ -195,4 +193,6 @@ static inline int ap_sta_is_authorized(struct sta_info *sta) void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta); void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta); +int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen); + #endif /* STA_INFO_H */ diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c index 4a2ea066..4725e2b3 100644 --- a/src/ap/tkip_countermeasures.c +++ b/src/ap/tkip_countermeasures.c @@ -68,7 +68,7 @@ void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd) int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) { - struct os_time now; + struct os_reltime now; int ret = 0; if (addr && local) { @@ -89,8 +89,8 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) } } - os_get_time(&now); - if (now.sec > hapd->michael_mic_failure + 60) { + os_get_reltime(&now); + if (os_reltime_expired(&now, &hapd->michael_mic_failure, 60)) { hapd->michael_mic_failures = 1; } else { hapd->michael_mic_failures++; @@ -99,7 +99,7 @@ int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) ret = 1; } } - hapd->michael_mic_failure = now.sec; + hapd->michael_mic_failure = now; return ret; } diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c index 1afbb8ec..509e557c 100644 --- a/src/ap/vlan_init.c +++ b/src/ap/vlan_init.c @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h index 382d5dee..781eaac4 100644 --- a/src/ap/vlan_init.h +++ b/src/ap/vlan_init.h @@ -3,14 +3,8 @@ * Copyright 2003, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef VLAN_INIT_H diff --git a/src/ap/wmm.c b/src/ap/wmm.c index 28516726..6d4177c2 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -4,14 +4,8 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2009, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" diff --git a/src/ap/wmm.h b/src/ap/wmm.h index 96b04e89..b70b8636 100644 --- a/src/ap/wmm.h +++ b/src/ap/wmm.h @@ -3,14 +3,8 @@ * Copyright 2002-2003, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef WME_H diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 54a6b857..8e5bdcb0 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -1,6 +1,6 @@ /* * hostapd - WNM - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,6 +9,7 @@ #include "utils/includes.h" #include "utils/common.h" +#include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "ap/hostapd.h" #include "ap/sta_info.h" @@ -72,7 +73,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, wnmsleep_ie.len = wnmsleep_ie_len - 2; wnmsleep_ie.action_type = action_type; wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT; - wnmsleep_ie.intval = intval; + wnmsleep_ie.intval = host_to_le16(intval); /* TFS IE(s) */ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); @@ -154,6 +155,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, */ if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT && wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) { + sta->flags |= WLAN_STA_WNM_SLEEP_MODE; hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM, addr, NULL, NULL); wpa_set_wnmsleep(sta->wpa_sm, 1); @@ -167,6 +169,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, wnmsleep_ie.status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) && wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) { + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; wpa_set_wnmsleep(sta->wpa_sm, 0); hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM, addr, NULL, NULL); @@ -233,7 +236,7 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token, wnmsleep_ie->action_type, - wnmsleep_ie->intval); + le_to_host16(wnmsleep_ie->intval)); if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { /* clear the tfs after sending the resp frame */ @@ -243,29 +246,263 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, } +static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, + const u8 *addr, + u8 dialog_token, + const char *url) +{ + struct ieee80211_mgmt *mgmt; + size_t url_len, len; + u8 *pos; + int res; + + if (url) + url_len = os_strlen(url); + else + url_len = 0; + + mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0)); + if (mgmt == NULL) + return -1; + os_memcpy(mgmt->da, addr, ETH_ALEN); + os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; + mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; + mgmt->u.action.u.bss_tm_req.req_mode = 0; + mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); + mgmt->u.action.u.bss_tm_req.validity_interval = 1; + pos = mgmt->u.action.u.bss_tm_req.variable; + if (url) { + *pos++ += url_len; + os_memcpy(pos, url, url_len); + pos += url_len; + } + + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " + MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u " + "validity_interval=%u", + MAC2STR(addr), dialog_token, + mgmt->u.action.u.bss_tm_req.req_mode, + le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer), + mgmt->u.action.u.bss_tm_req.validity_interval); + + len = pos - &mgmt->u.action.category; + res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, + mgmt->da, &mgmt->u.action.category, len); + os_free(mgmt); + return res; +} + + +static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, + const u8 *addr, const u8 *frm, + size_t len) +{ + u8 dialog_token, reason; + const u8 *pos, *end; + + if (len < 2) { + wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from " + MACSTR, MAC2STR(addr)); + return; + } + + pos = frm; + end = pos + len; + dialog_token = *pos++; + reason = *pos++; + + wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from " + MACSTR " dialog_token=%u reason=%u", + MAC2STR(addr), dialog_token, reason); + + wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", + pos, end - pos); + + ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL); +} + + +static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd, + const u8 *addr, const u8 *frm, + size_t len) +{ + u8 dialog_token, status_code, bss_termination_delay; + const u8 *pos, *end; + + if (len < 3) { + wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from " + MACSTR, MAC2STR(addr)); + return; + } + + pos = frm; + end = pos + len; + dialog_token = *pos++; + status_code = *pos++; + bss_termination_delay = *pos++; + + wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from " + MACSTR " dialog_token=%u status_code=%u " + "bss_termination_delay=%u", MAC2STR(addr), dialog_token, + status_code, bss_termination_delay); + + if (status_code == WNM_BSS_TM_ACCEPT) { + if (end - pos < ETH_ALEN) { + wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field"); + return; + } + wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR, + MAC2STR(pos)); + pos += ETH_ALEN; + } + + wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", + pos, end - pos); +} + + int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, - struct rx_action *action) + const struct ieee80211_mgmt *mgmt, size_t len) { - if (action->len < 1 || action->data == NULL) + u8 action; + const u8 *payload; + size_t plen; + + if (len < IEEE80211_HDRLEN + 2) return -1; - switch (action->data[0]) { + payload = &mgmt->u.action.category; + payload++; + action = *payload++; + plen = (((const u8 *) mgmt) + len) - payload; + + switch (action) { case WNM_BSS_TRANS_MGMT_QUERY: - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query"); - /* TODO */ - return -1; + ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, + plen); + return 0; case WNM_BSS_TRANS_MGMT_RESP: - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management " - "Response"); - /* TODO */ - return -1; + ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload, + plen); + return 0; case WNM_SLEEP_MODE_REQ: - ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1, - action->len - 1); + ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen); return 0; } wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR, - action->data[0], MAC2STR(action->sa)); + action, MAC2STR(mgmt->sa)); return -1; } + + +int wnm_send_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, int disassoc_timer) +{ + u8 buf[1000], *pos; + struct ieee80211_mgmt *mgmt; + + os_memset(buf, 0, sizeof(buf)); + mgmt = (struct ieee80211_mgmt *) buf; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt->da, sta->addr, ETH_ALEN); + os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; + mgmt->u.action.u.bss_tm_req.dialog_token = 1; + mgmt->u.action.u.bss_tm_req.req_mode = + WNM_BSS_TM_REQ_DISASSOC_IMMINENT; + mgmt->u.action.u.bss_tm_req.disassoc_timer = + host_to_le16(disassoc_timer); + mgmt->u.action.u.bss_tm_req.validity_interval = 0; + + pos = mgmt->u.action.u.bss_tm_req.variable; + + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to " + MACSTR, disassoc_timer, MAC2STR(sta->addr)); + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " + "Management Request frame"); + return -1; + } + + return 0; +} + + +int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, const char *url, + int disassoc_timer) +{ + u8 buf[1000], *pos; + struct ieee80211_mgmt *mgmt; + size_t url_len; + + os_memset(buf, 0, sizeof(buf)); + mgmt = (struct ieee80211_mgmt *) buf; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memcpy(mgmt->da, sta->addr, ETH_ALEN); + os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + mgmt->u.action.category = WLAN_ACTION_WNM; + mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; + mgmt->u.action.u.bss_tm_req.dialog_token = 1; + mgmt->u.action.u.bss_tm_req.req_mode = + WNM_BSS_TM_REQ_DISASSOC_IMMINENT | + WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; + mgmt->u.action.u.bss_tm_req.disassoc_timer = + host_to_le16(disassoc_timer); + mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; + + pos = mgmt->u.action.u.bss_tm_req.variable; + + /* Session Information URL */ + url_len = os_strlen(url); + if (url_len > 255) + return -1; + *pos++ = url_len; + os_memcpy(pos, url, url_len); + pos += url_len; + + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " + "Management Request frame"); + return -1; + } + + /* send disassociation frame after time-out */ + if (disassoc_timer) { + int timeout, beacon_int; + + /* + * Prevent STA from reconnecting using cached PMKSA to force + * full authentication with the authentication server (which may + * decide to reject the connection), + */ + wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); + + beacon_int = hapd->iconf->beacon_int; + if (beacon_int < 1) + beacon_int = 100; /* best guess */ + /* Calculate timeout in ms based on beacon_int in TU */ + timeout = disassoc_timer * beacon_int * 128 / 125; + wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR + " set to %d ms", MAC2STR(sta->addr), timeout); + + sta->timeout_next = STA_DISASSOC_FROM_CLI; + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_register_timeout(timeout / 1000, + timeout % 1000 * 1000, + ap_handle_timer, hapd, sta); + } + + return 0; +} diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h index f05726ee..eeaf5eca 100644 --- a/src/ap/wnm_ap.h +++ b/src/ap/wnm_ap.h @@ -1,6 +1,6 @@ /* * IEEE 802.11v WNM related functions and structures - * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,9 +9,14 @@ #ifndef WNM_AP_H #define WNM_AP_H -struct rx_action; +struct sta_info; int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, - struct rx_action *action); + const struct ieee80211_mgmt *mgmt, size_t len); +int wnm_send_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, int disassoc_timer); +int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, + struct sta_info *sta, const char *url, + int disassoc_timer); #endif /* WNM_AP_H */ diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 03b15c24..5993edf7 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -437,6 +437,8 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth) wpa_group_sm_step(wpa_auth, group); group->GInit = FALSE; wpa_group_sm_step(wpa_auth, group); + if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + return -1; return 0; } @@ -516,6 +518,9 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, { struct wpa_state_machine *sm; + if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + return NULL; + sm = os_zalloc(sizeof(struct wpa_state_machine)); if (sm == NULL) return NULL; @@ -2452,7 +2457,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) /* update GTK when exiting WNM-Sleep Mode */ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm) { - if (sm->is_wnmsleep) + if (sm == NULL || sm->is_wnmsleep) return; wpa_group_update_sta(sm, NULL); @@ -2461,7 +2466,8 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm) void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag) { - sm->is_wnmsleep = !!flag; + if (sm) + sm->is_wnmsleep = !!flag; } @@ -2587,6 +2593,29 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, } +static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx) +{ + if (sm->group == ctx) { + wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR + " for discconnection due to fatal failure", + MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + } + + return 0; +} + + +static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE"); + group->changed = TRUE; + group->wpa_group_state = WPA_GROUP_FATAL_FAILURE; + wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group); +} + + static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { @@ -2595,8 +2624,10 @@ static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, group->changed = TRUE; group->wpa_group_state = WPA_GROUP_SETKEYSDONE; - if (wpa_group_config_group_keys(wpa_auth, group) < 0) + if (wpa_group_config_group_keys(wpa_auth, group) < 0) { + wpa_group_fatal_failure(wpa_auth, group); return -1; + } return 0; } @@ -2607,6 +2638,8 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, { if (group->GInit) { wpa_group_gtk_init(wpa_auth, group); + } else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) { + /* Do not allow group operations */ } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT && group->GTKAuthenticator) { wpa_group_setkeysdone(wpa_auth, group); @@ -3015,6 +3048,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) if (sm->group == group) return 0; + if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) + return -1; + wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state " "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id); @@ -3059,3 +3095,11 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm) return 0; return wpa_key_mgmt_sae(sm->wpa_key_mgmt); } + + +int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm) +{ + if (sm == NULL) + return 0; + return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE; +} diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 47503d00..da45ae40 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -203,7 +203,7 @@ struct wpa_auth_callbacks { int (*send_ft_action)(void *ctx, const u8 *dst, const u8 *data, size_t data_len); int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie, - size_t tspec_ielen); + size_t tspec_ielen); #endif /* CONFIG_IEEE80211R */ }; @@ -295,5 +295,6 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos); int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos); int wpa_auth_uses_sae(struct wpa_state_machine *sm); +int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm); #endif /* WPA_AUTH_H */ diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 29d9d29e..c22c4cca 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -57,7 +57,7 @@ static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth, u8 *tspec_ie, size_t tspec_ielen) { if (wpa_auth->cb.add_tspec == NULL) { - wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized"); + wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized"); return -1; } return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie, @@ -570,8 +570,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, else { /* TSPEC accepted; include updated TSPEC in * response */ - rdie->descr_count = 1; - pos += sizeof(*tspec); + rdie->descr_count = 1; + pos += sizeof(*tspec); } return pos; } @@ -633,8 +633,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, conf = &sm->wpa_auth->conf; - if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK) + if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt)) return pos; end = pos + max_len; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index cbaab9f0..4c1d6257 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -15,7 +15,6 @@ #include "eapol_auth/eapol_auth_sm_i.h" #include "eap_server/eap.h" #include "l2_packet/l2_packet.h" -#include "drivers/driver.h" #include "hostapd.h" #include "ieee802_1x.h" #include "preauth_auth.h" diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 12e59bc4..9736874f 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -139,7 +139,8 @@ struct wpa_group { enum { WPA_GROUP_GTK_INIT = 0, - WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE + WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE, + WPA_GROUP_FATAL_FAILURE } wpa_group_state; u8 GMK[WPA_GMK_LEN]; diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 294a39d6..4c94210e 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -287,6 +287,20 @@ static void wps_reload_config(void *eloop_data, void *user_ctx) } +void hostapd_wps_eap_completed(struct hostapd_data *hapd) +{ + /* + * Reduce race condition of the station trying to reconnect immediately + * after AP reconfiguration through WPS by rescheduling the reload + * timeout to happen after EAP completion rather than the originally + * scheduled 100 ms after new configuration became known. + */ + if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL) == + 1) + wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload"); +} + + static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr, size_t attr_len) { @@ -1227,6 +1241,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd) { eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); + eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL); if (hapd->wps == NULL) return; #ifdef CONFIG_WPS_UPNP diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h index a2c2cf02..a292598b 100644 --- a/src/ap/wps_hostapd.h +++ b/src/ap/wps_hostapd.h @@ -16,6 +16,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, int hostapd_init_wps_complete(struct hostapd_data *hapd); void hostapd_deinit_wps(struct hostapd_data *hapd); void hostapd_update_wps(struct hostapd_data *hapd); +void hostapd_wps_eap_completed(struct hostapd_data *hapd); int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, const char *uuid, const char *pin, int timeout); int hostapd_wps_button_pushed(struct hostapd_data *hapd, @@ -61,6 +62,10 @@ static inline void hostapd_update_wps(struct hostapd_data *hapd) { } +static inline void hostapd_wps_eap_completed(struct hostapd_data *hapd) +{ +} + static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, char *buf, size_t buflen) diff --git a/src/common/defs.h b/src/common/defs.h index 0c90c249..4811e8e9 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -23,11 +23,15 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_CIPHER_WEP104 BIT(2) #define WPA_CIPHER_TKIP BIT(3) #define WPA_CIPHER_CCMP BIT(4) -#ifdef CONFIG_IEEE80211W #define WPA_CIPHER_AES_128_CMAC BIT(5) -#endif /* CONFIG_IEEE80211W */ #define WPA_CIPHER_GCMP BIT(6) #define WPA_CIPHER_SMS4 BIT(7) +#define WPA_CIPHER_GCMP_256 BIT(8) +#define WPA_CIPHER_CCMP_256 BIT(9) +#define WPA_CIPHER_BIP_GMAC_128 BIT(11) +#define WPA_CIPHER_BIP_GMAC_256 BIT(12) +#define WPA_CIPHER_BIP_CMAC_256 BIT(13) +#define WPA_CIPHER_GTK_NOT_USED BIT(14) #define WPA_KEY_MGMT_IEEE8021X BIT(0) #define WPA_KEY_MGMT_PSK BIT(1) @@ -58,7 +62,8 @@ static inline int wpa_key_mgmt_wpa_psk(int akm) return !!(akm & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256 | - WPA_KEY_MGMT_SAE)); + WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_FT_SAE)); } static inline int wpa_key_mgmt_ft(int akm) @@ -83,7 +88,8 @@ static inline int wpa_key_mgmt_sha256(int akm) static inline int wpa_key_mgmt_wpa(int akm) { return wpa_key_mgmt_wpa_ieee8021x(akm) || - wpa_key_mgmt_wpa_psk(akm); + wpa_key_mgmt_wpa_psk(akm) || + wpa_key_mgmt_sae(akm); } static inline int wpa_key_mgmt_wpa_any(int akm) @@ -117,41 +123,12 @@ enum wpa_alg { WPA_ALG_PMK, WPA_ALG_GCMP, WPA_ALG_SMS4, - WPA_ALG_KRK -}; - -/** - * enum wpa_cipher - Cipher suites - */ -enum wpa_cipher { - CIPHER_NONE, - CIPHER_WEP40, - CIPHER_TKIP, - CIPHER_CCMP, - CIPHER_WEP104, - CIPHER_GCMP, - CIPHER_SMS4 -}; - -/** - * enum wpa_key_mgmt - Key management suites - */ -enum wpa_key_mgmt { - KEY_MGMT_802_1X, - KEY_MGMT_PSK, - KEY_MGMT_NONE, - KEY_MGMT_802_1X_NO_WPA, - KEY_MGMT_WPA_NONE, - KEY_MGMT_FT_802_1X, - KEY_MGMT_FT_PSK, - KEY_MGMT_802_1X_SHA256, - KEY_MGMT_PSK_SHA256, - KEY_MGMT_WPS, - KEY_MGMT_SAE, - KEY_MGMT_FT_SAE, - KEY_MGMT_WAPI_PSK, - KEY_MGMT_WAPI_CERT, - KEY_MGMT_CCKM + WPA_ALG_KRK, + WPA_ALG_GCMP_256, + WPA_ALG_CCMP_256, + WPA_ALG_BIP_GMAC_128, + WPA_ALG_BIP_GMAC_256, + WPA_ALG_BIP_CMAC_256 }; /** diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 304dfc69..809089fa 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -189,25 +189,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->supp_rates = pos; elems->supp_rates_len = elen; break; - case WLAN_EID_FH_PARAMS: - elems->fh_params = pos; - elems->fh_params_len = elen; - break; case WLAN_EID_DS_PARAMS: elems->ds_params = pos; elems->ds_params_len = elen; break; case WLAN_EID_CF_PARAMS: - elems->cf_params = pos; - elems->cf_params_len = elen; - break; case WLAN_EID_TIM: - elems->tim = pos; - elems->tim_len = elen; - break; - case WLAN_EID_IBSS_PARAMS: - elems->ibss_params = pos; - elems->ibss_params_len = elen; break; case WLAN_EID_CHALLENGE: elems->challenge = pos; @@ -232,8 +219,6 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->rsn_ie_len = elen; break; case WLAN_EID_PWR_CAPABILITY: - elems->power_cap = pos; - elems->power_cap_len = elen; break; case WLAN_EID_SUPPORTED_CHANNELS: elems->supp_channels = pos; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index c4618b2d..b84dd9e7 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -13,11 +13,7 @@ struct ieee802_11_elems { const u8 *ssid; const u8 *supp_rates; - const u8 *fh_params; const u8 *ds_params; - const u8 *cf_params; - const u8 *tim; - const u8 *ibss_params; const u8 *challenge; const u8 *erp_info; const u8 *ext_supp_rates; @@ -26,7 +22,6 @@ struct ieee802_11_elems { const u8 *wmm; /* WMM Information or Parameter Element */ const u8 *wmm_tspec; const u8 *wps_ie; - const u8 *power_cap; const u8 *supp_channels; const u8 *mdie; const u8 *ftie; @@ -48,11 +43,7 @@ struct ieee802_11_elems { u8 ssid_len; u8 supp_rates_len; - u8 fh_params_len; u8 ds_params_len; - u8 cf_params_len; - u8 tim_len; - u8 ibss_params_len; u8 challenge_len; u8 erp_info_len; u8 ext_supp_rates_len; @@ -61,7 +52,6 @@ struct ieee802_11_elems { u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */ u8 wmm_tspec_len; u8 wps_ie_len; - u8 power_cap_len; u8 supp_channels_len; u8 mdie_len; u8 ftie_len; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 9b2d54f4..7d786483 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -161,6 +161,7 @@ #define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76 #define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77 #define WLAN_STATUS_TRANSMISSION_FAILURE 79 +#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ #define WLAN_REASON_UNSPECIFIED 1 @@ -1024,6 +1025,11 @@ enum wifi_display_subelem { #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 #define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07 #define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 +#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09 +#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0A +#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B +#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C +#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D #define WLAN_CIPHER_SUITE_SMS4 0x00147201 diff --git a/src/common/sae.c b/src/common/sae.c index 4e9e4610..08bf054c 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -701,6 +701,11 @@ static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; } + if (sae->tmp == NULL) { + wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + if (sae->tmp->dh && !allowed_groups) { wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without " "explicit configuration enabling it", group); @@ -797,7 +802,7 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, /* element x and y coordinates < p */ if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 || - os_memcmp(pos + sae->tmp->prime_len + sae->tmp->prime_len, prime, + os_memcmp(pos + sae->tmp->prime_len, prime, sae->tmp->prime_len) >= 0) { wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer " "element"); diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index c3afbfd3..37b265d0 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -353,6 +353,16 @@ static int rsn_selector_to_bitfield(const u8 *s) #endif /* CONFIG_IEEE80211W */ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) return WPA_CIPHER_GCMP; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256) + return WPA_CIPHER_GCMP_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128) + return WPA_CIPHER_BIP_GMAC_128; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256) + return WPA_CIPHER_BIP_GMAC_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) + return WPA_CIPHER_BIP_CMAC_256; return 0; } @@ -912,6 +922,12 @@ const char * wpa_cipher_txt(int cipher) return "CCMP+TKIP"; case WPA_CIPHER_GCMP: return "GCMP"; + case WPA_CIPHER_GCMP_256: + return "GCMP-256"; + case WPA_CIPHER_CCMP_256: + return "CCMP-256"; + case WPA_CIPHER_GTK_NOT_USED: + return "GTK_NOT_USED"; default: return "UNKNOWN"; } @@ -1078,6 +1094,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) int wpa_cipher_key_len(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + case WPA_CIPHER_GCMP_256: + return 32; case WPA_CIPHER_CCMP: case WPA_CIPHER_GCMP: return 16; @@ -1096,6 +1115,8 @@ int wpa_cipher_key_len(int cipher) int wpa_cipher_rsc_len(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + case WPA_CIPHER_GCMP_256: case WPA_CIPHER_CCMP: case WPA_CIPHER_GCMP: case WPA_CIPHER_TKIP: @@ -1112,6 +1133,10 @@ int wpa_cipher_rsc_len(int cipher) int wpa_cipher_to_alg(int cipher) { switch (cipher) { + case WPA_CIPHER_CCMP_256: + return WPA_ALG_CCMP_256; + case WPA_CIPHER_GCMP_256: + return WPA_ALG_GCMP_256; case WPA_CIPHER_CCMP: return WPA_ALG_CCMP; case WPA_CIPHER_GCMP: @@ -1126,29 +1151,11 @@ int wpa_cipher_to_alg(int cipher) } -enum wpa_cipher wpa_cipher_to_suite_driver(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_NONE: - return CIPHER_NONE; - case WPA_CIPHER_WEP40: - return CIPHER_WEP40; - case WPA_CIPHER_WEP104: - return CIPHER_WEP104; - case WPA_CIPHER_CCMP: - return CIPHER_CCMP; - case WPA_CIPHER_GCMP: - return CIPHER_GCMP; - case WPA_CIPHER_TKIP: - default: - return CIPHER_TKIP; - } -} - - int wpa_cipher_valid_pairwise(int cipher) { - return cipher == WPA_CIPHER_CCMP || + return cipher == WPA_CIPHER_CCMP_256 || + cipher == WPA_CIPHER_GCMP_256 || + cipher == WPA_CIPHER_CCMP || cipher == WPA_CIPHER_GCMP || cipher == WPA_CIPHER_TKIP; } @@ -1156,6 +1163,10 @@ int wpa_cipher_valid_pairwise(int cipher) u32 wpa_cipher_to_suite(int proto, int cipher) { + if (cipher & WPA_CIPHER_CCMP_256) + return RSN_CIPHER_SUITE_CCMP_256; + if (cipher & WPA_CIPHER_GCMP_256) + return RSN_CIPHER_SUITE_GCMP_256; if (cipher & WPA_CIPHER_CCMP) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); @@ -1173,6 +1184,8 @@ u32 wpa_cipher_to_suite(int proto, int cipher) if (cipher & WPA_CIPHER_NONE) return (proto == WPA_PROTO_RSN ? RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); + if (cipher & WPA_CIPHER_GTK_NOT_USED) + return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; return 0; } @@ -1181,6 +1194,16 @@ int rsn_cipher_put_suites(u8 *pos, int ciphers) { int num_suites = 0; + if (ciphers & WPA_CIPHER_CCMP_256) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (ciphers & WPA_CIPHER_GCMP_256) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256); + pos += RSN_SELECTOR_LEN; + num_suites++; + } if (ciphers & WPA_CIPHER_CCMP) { RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); pos += RSN_SELECTOR_LEN; @@ -1232,6 +1255,10 @@ int wpa_cipher_put_suites(u8 *pos, int ciphers) int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) { + if (ciphers & WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (ciphers & WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; if (ciphers & WPA_CIPHER_CCMP) return WPA_CIPHER_CCMP; if (ciphers & WPA_CIPHER_GCMP) @@ -1246,10 +1273,16 @@ int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) int wpa_pick_group_cipher(int ciphers) { + if (ciphers & WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; + if (ciphers & WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; if (ciphers & WPA_CIPHER_CCMP) return WPA_CIPHER_CCMP; if (ciphers & WPA_CIPHER_GCMP) return WPA_CIPHER_GCMP; + if (ciphers & WPA_CIPHER_GTK_NOT_USED) + return WPA_CIPHER_GTK_NOT_USED; if (ciphers & WPA_CIPHER_TKIP) return WPA_CIPHER_TKIP; if (ciphers & WPA_CIPHER_WEP104) @@ -1280,7 +1313,11 @@ int wpa_parse_cipher(const char *value) end++; last = *end == '\0'; *end = '\0'; - if (os_strcmp(start, "CCMP") == 0) + if (os_strcmp(start, "CCMP-256") == 0) + val |= WPA_CIPHER_CCMP_256; + else if (os_strcmp(start, "GCMP-256") == 0) + val |= WPA_CIPHER_GCMP_256; + else if (os_strcmp(start, "CCMP") == 0) val |= WPA_CIPHER_CCMP; else if (os_strcmp(start, "GCMP") == 0) val |= WPA_CIPHER_GCMP; @@ -1292,6 +1329,8 @@ int wpa_parse_cipher(const char *value) val |= WPA_CIPHER_WEP40; else if (os_strcmp(start, "NONE") == 0) val |= WPA_CIPHER_NONE; + else if (os_strcmp(start, "GTK_NOT_USED") == 0) + val |= WPA_CIPHER_GTK_NOT_USED; else { os_free(buf); return -1; @@ -1312,6 +1351,20 @@ int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim) char *pos = start; int ret; + if (ciphers & WPA_CIPHER_CCMP_256) { + ret = os_snprintf(pos, end - pos, "%sCCMP-256", + pos == start ? "" : delim); + if (ret < 0 || ret >= end - pos) + return -1; + pos += ret; + } + if (ciphers & WPA_CIPHER_GCMP_256) { + ret = os_snprintf(pos, end - pos, "%sGCMP-256", + pos == start ? "" : delim); + if (ret < 0 || ret >= end - pos) + return -1; + pos += ret; + } if (ciphers & WPA_CIPHER_CCMP) { ret = os_snprintf(pos, end - pos, "%sCCMP", pos == start ? "" : delim); @@ -1373,5 +1426,11 @@ int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise) return WPA_CIPHER_TKIP; if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP) return WPA_CIPHER_GCMP; + if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP | + WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256) + return WPA_CIPHER_GCMP_256; + if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP | + WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256) + return WPA_CIPHER_CCMP_256; return WPA_CIPHER_CCMP; } diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 2d636623..62505f1b 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -21,10 +21,12 @@ #define WPA_GTK_MAX_LEN 32 #define WPA_ALLOWED_PAIRWISE_CIPHERS \ -(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE) +(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \ +WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256) #define WPA_ALLOWED_GROUP_CIPHERS \ (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \ -WPA_CIPHER_WEP40) +WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \ +WPA_CIPHER_GTK_NOT_USED) #define WPA_SELECTOR_LEN 4 #define WPA_VERSION 1 @@ -60,6 +62,10 @@ WPA_CIPHER_WEP40) #define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8) #define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9) +#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11) +#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_384 RSN_SELECTOR(0x00, 0x0f, 0xac, 12) +#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384 \ +RSN_SELECTOR(0x00, 0x0f, 0xac, 13) #define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00) #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) @@ -75,6 +81,11 @@ WPA_CIPHER_WEP40) #endif /* CONFIG_IEEE80211W */ #define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) +#define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9) +#define RSN_CIPHER_SUITE_CCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 10) +#define RSN_CIPHER_SUITE_BIP_GMAC_128 RSN_SELECTOR(0x00, 0x0f, 0xac, 11) +#define RSN_CIPHER_SUITE_BIP_GMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 12) +#define RSN_CIPHER_SUITE_BIP_CMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 13) /* EAPOL-Key Key Data Encapsulation * GroupKey and PeerKey require encryption, otherwise, encryption is optional. @@ -392,7 +403,6 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse); int wpa_cipher_key_len(int cipher); int wpa_cipher_rsc_len(int cipher); int wpa_cipher_to_alg(int cipher); -enum wpa_cipher wpa_cipher_to_suite_driver(int cipher); int wpa_cipher_valid_pairwise(int cipher); u32 wpa_cipher_to_suite(int proto, int cipher); int rsn_cipher_put_suites(u8 *pos, int ciphers); diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 83788d7d..f4af94aa 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -391,7 +391,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, void (*msg_cb)(char *msg, size_t len)) { struct timeval tv; - struct os_time started_at; + struct os_reltime started_at; int res; fd_set rfds; const char *_cmd; @@ -430,12 +430,12 @@ retry_send: * longer before giving up. */ if (started_at.sec == 0) - os_get_time(&started_at); + os_get_reltime(&started_at); else { - struct os_time n; - os_get_time(&n); + struct os_reltime n; + os_get_reltime(&n); /* Try for a few seconds. */ - if (n.sec > started_at.sec + 5) + if (os_reltime_expired(&n, &started_at, 5)) goto send_err; } os_sleep(1, 0); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 88bfb4d9..9bd59a9c 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -54,6 +54,8 @@ extern "C" { #define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED " /** Temporarily disabled network block re-enabled */ #define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED " +/** New scan started */ +#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED " /** New scan results available */ #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " /** wpa_supplicant state change */ @@ -145,6 +147,7 @@ extern "C" { #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT " #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED " #define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id=" +#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE " /* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */ #define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " @@ -154,6 +157,13 @@ extern "C" { #define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED " #define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO " +/* parameters: <addr> <dialog_token> <freq> */ +#define GAS_QUERY_START "GAS-QUERY-START " +/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */ +#define GAS_QUERY_DONE "GAS-QUERY-DONE " + +#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START " +#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT " /* hostapd control interface - fixed message prefixes */ #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index 5215c00f..1da2b9f4 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -26,6 +26,8 @@ #include "common.h" #include "wpabuf.h" #include "dh_group5.h" +#include "sha1.h" +#include "sha256.h" #include "crypto.h" #if OPENSSL_VERSION_NUMBER < 0x00907000 diff --git a/src/crypto/tls.h b/src/crypto/tls.h index feba13ff..287fd333 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -41,7 +41,8 @@ enum tls_fail_reason { TLS_FAIL_ALTSUBJECT_MISMATCH = 6, TLS_FAIL_BAD_CERTIFICATE = 7, TLS_FAIL_SERVER_CHAIN_PROBE = 8, - TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9 + TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9, + TLS_FAIL_SERVER_USED_CLIENT_CERT = 10 }; union tls_event_data { diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index a5d72f40..cb23eb9c 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -125,8 +125,6 @@ static void tls_log_func(int level, const char *msg) } -extern int wpa_debug_show_keys; - void * tls_init(const struct tls_config *conf) { struct tls_global *global; diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index eeaf859f..4cfa5f43 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -105,6 +105,7 @@ struct tls_connection { unsigned int ca_cert_verify:1; unsigned int cert_probe:1; unsigned int server_cert_only:1; + unsigned int server:1; u8 srv_cert_hash[32]; @@ -112,6 +113,7 @@ struct tls_connection { X509 *peer_cert; X509 *peer_issuer; + X509 *peer_issuer_issuer; }; @@ -1385,6 +1387,8 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) conn->peer_cert = err_cert; else if (depth == 1) conn->peer_issuer = err_cert; + else if (depth == 2) + conn->peer_issuer_issuer = err_cert; context = conn->context; match = conn->subject_match; @@ -1478,6 +1482,16 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) TLS_FAIL_SERVER_CHAIN_PROBE); } + if (!conn->server && err_cert && preverify_ok && depth == 0 && + (err_cert->ex_flags & EXFLAG_XKUSAGE) && + (err_cert->ex_xkusage & XKU_SSL_CLIENT)) { + wpa_printf(MSG_WARNING, "TLS: Server used client certificate"); + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Server used client certificate", + TLS_FAIL_SERVER_USED_CLIENT_CERT); + preverify_ok = 0; + } + if (preverify_ok && context->event_cb != NULL) context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_SUCCESS, NULL); @@ -2529,6 +2543,8 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, int res; struct wpabuf *out_data; + conn->server = !!server; + /* * Give TLS handshake data from the server (if available) to OpenSSL * for processing. @@ -2890,7 +2906,6 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) { #ifndef CONFIG_NO_STDOUT_DEBUG - extern int wpa_debug_level; BIO *out; size_t rlen; char *txt; @@ -2931,6 +2946,8 @@ static int ocsp_resp_cb(SSL *s, void *arg) OCSP_BASICRESP *basic; OCSP_CERTID *id; ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; + X509_STORE *store; + STACK_OF(X509) *certs = NULL; len = SSL_get_tlsext_status_ocsp_resp(s, &p); if (!p) { @@ -2961,8 +2978,41 @@ static int ocsp_resp_cb(SSL *s, void *arg) return 0; } - status = OCSP_basic_verify(basic, NULL, SSL_CTX_get_cert_store(s->ctx), - 0); + store = SSL_CTX_get_cert_store(s->ctx); + if (conn->peer_issuer) { + wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); + X509_print_fp(stdout, conn->peer_issuer); + + if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) { + tls_show_errors(MSG_INFO, __func__, + "OpenSSL: Could not add issuer to certificate store\n"); + } + certs = sk_X509_new_null(); + if (certs) { + X509 *cert; + cert = X509_dup(conn->peer_issuer); + if (cert && !sk_X509_push(certs, cert)) { + tls_show_errors( + MSG_INFO, __func__, + "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + X509_free(cert); + sk_X509_free(certs); + certs = NULL; + } + if (conn->peer_issuer_issuer) { + cert = X509_dup(conn->peer_issuer_issuer); + if (cert && !sk_X509_push(certs, cert)) { + tls_show_errors( + MSG_INFO, __func__, + "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + X509_free(cert); + } + } + } + } + + status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); + sk_X509_pop_free(certs, X509_free); if (status <= 0) { tls_show_errors(MSG_INFO, __func__, "OpenSSL: OCSP response failed verification"); diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h index 5906527a..31d94408 100644 --- a/src/drivers/android_drv.h +++ b/src/drivers/android_drv.h @@ -1,12 +1,8 @@ /* * Android driver interface * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #ifndef ANDROID_DRV_H diff --git a/src/drivers/driver.h b/src/drivers/driver.h index a3602ed7..db34ed13 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1,6 +1,6 @@ /* * Driver interface definition - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -233,7 +233,7 @@ struct wpa_scan_res { struct wpa_scan_results { struct wpa_scan_res **res; size_t num; - struct os_time fetch_time; + struct os_reltime fetch_time; }; /** @@ -340,6 +340,21 @@ struct wpa_driver_scan_params { * and not to transmit the frames at any of those rates. */ u8 p2p_probe; + + /** + * only_new_results - Request driver to report only new results + * + * This is used to request the driver to report only BSSes that have + * been detected after this scan request has been started, i.e., to + * flush old cached BSS entries. + */ + int only_new_results; + + /* + * NOTE: Whenever adding new parameters here, please make sure + * wpa_scan_clone_params() and wpa_scan_free_params() get updated with + * matching changes. + */ }; /** @@ -442,25 +457,25 @@ struct wpa_driver_associate_params { unsigned int wpa_proto; /** - * pairwise_suite - Selected pairwise cipher suite + * pairwise_suite - Selected pairwise cipher suite (WPA_CIPHER_*) * * This is usually ignored if @wpa_ie is used. */ - enum wpa_cipher pairwise_suite; + unsigned int pairwise_suite; /** - * group_suite - Selected group cipher suite + * group_suite - Selected group cipher suite (WPA_CIPHER_*) * * This is usually ignored if @wpa_ie is used. */ - enum wpa_cipher group_suite; + unsigned int group_suite; /** - * key_mgmt_suite - Selected key management suite + * key_mgmt_suite - Selected key management suite (WPA_KEY_MGMT_*) * * This is usually ignored if @wpa_ie is used. */ - enum wpa_key_mgmt key_mgmt_suite; + unsigned int key_mgmt_suite; /** * auth_alg - Allowed authentication algorithms @@ -833,6 +848,12 @@ struct wpa_driver_capa { #define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008 #define WPA_DRIVER_CAPA_ENC_WEP128 0x00000010 #define WPA_DRIVER_CAPA_ENC_GCMP 0x00000020 +#define WPA_DRIVER_CAPA_ENC_GCMP_256 0x00000040 +#define WPA_DRIVER_CAPA_ENC_CCMP_256 0x00000080 +#define WPA_DRIVER_CAPA_ENC_BIP 0x00000100 +#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_128 0x00000200 +#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256 0x00000400 +#define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256 0x00000800 unsigned int enc; #define WPA_DRIVER_AUTH_OPEN 0x00000001 @@ -856,8 +877,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_AP 0x00000040 /* Driver needs static WEP key setup after association has been completed */ #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080 -/* Driver takes care of P2P management operations */ -#define WPA_DRIVER_FLAGS_P2P_MGMT 0x00000100 +/* unused: 0x00000100 */ /* Driver supports concurrent P2P operations */ #define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200 /* @@ -910,6 +930,10 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_RADAR 0x10000000 /* Driver supports a dedicated interface for P2P Device */ #define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE 0x20000000 +/* Driver supports QoS Mapping */ +#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000 +/* Driver supports CSA in AP mode */ +#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000 unsigned int flags; int max_scan_ssids; @@ -1099,17 +1123,6 @@ struct wpa_bss_params { #define WPA_STA_MFP BIT(3) #define WPA_STA_TDLS_PEER BIT(4) -/** - * struct p2p_params - P2P parameters for driver-based P2P management - */ -struct p2p_params { - const char *dev_name; - u8 pri_dev_type[8]; -#define DRV_MAX_SEC_DEV_TYPES 5 - u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8]; - size_t num_sec_dev_types; -}; - enum tdls_oper { TDLS_DISCOVERY_REQ, TDLS_SETUP, @@ -1265,7 +1278,9 @@ struct wpa_driver_ops { * @priv: private driver interface data * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK, - * %WPA_ALG_GCMP); + * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256, + * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, + * %WPA_ALG_BIP_CMAC_256); * %WPA_ALG_NONE clears the key. * @addr: Address of the peer STA (BSSID of the current AP when setting * pairwise key in station mode), ff:ff:ff:ff:ff:ff for @@ -2206,7 +2221,7 @@ struct wpa_driver_ops { * * This command is used to request the driver to remain awake on the * specified channel for the specified duration and report received - * Action frames with EVENT_RX_ACTION events. Optionally, received + * Action frames with EVENT_RX_MGMT events. Optionally, received * Probe Request frames may also be requested to be reported by calling * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ. * @@ -2388,222 +2403,6 @@ struct wpa_driver_ops { const char * (*get_radio_name)(void *priv); /** - * p2p_find - Start P2P Device Discovery - * @priv: Private driver interface data - * @timeout: Timeout for find operation in seconds or 0 for no timeout - * @type: Device Discovery type (enum p2p_discovery_type) - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_find)(void *priv, unsigned int timeout, int type); - - /** - * p2p_stop_find - Stop P2P Device Discovery - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_stop_find)(void *priv); - - /** - * p2p_listen - Start P2P Listen state for specified duration - * @priv: Private driver interface data - * @timeout: Listen state duration in milliseconds - * Returns: 0 on success, -1 on failure - * - * This function can be used to request the P2P module to keep the - * device discoverable on the listen channel for an extended set of - * time. At least in its current form, this is mainly used for testing - * purposes and may not be of much use for normal P2P operations. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_listen)(void *priv, unsigned int timeout); - - /** - * p2p_connect - Start P2P group formation (GO negotiation) - * @priv: Private driver interface data - * @peer_addr: MAC address of the peer P2P client - * @wps_method: enum p2p_wps_method value indicating config method - * @go_intent: Local GO intent value (1..15) - * @own_interface_addr: Intended interface address to use with the - * group - * @force_freq: The only allowed channel frequency in MHz or 0 - * @persistent_group: Whether to create persistent group - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method, - int go_intent, const u8 *own_interface_addr, - unsigned int force_freq, int persistent_group); - - /** - * wps_success_cb - Report successfully completed WPS provisioning - * @priv: Private driver interface data - * @peer_addr: Peer address - * Returns: 0 on success, -1 on failure - * - * This function is used to report successfully completed WPS - * provisioning during group formation in both GO/Registrar and - * client/Enrollee roles. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*wps_success_cb)(void *priv, const u8 *peer_addr); - - /** - * p2p_group_formation_failed - Report failed WPS provisioning - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure - * - * This function is used to report failed group formation. This can - * happen either due to failed WPS provisioning or due to 15 second - * timeout during the provisioning phase. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_group_formation_failed)(void *priv); - - /** - * p2p_set_params - Set P2P parameters - * @priv: Private driver interface data - * @params: P2P parameters - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_set_params)(void *priv, const struct p2p_params *params); - - /** - * p2p_prov_disc_req - Send Provision Discovery Request - * @priv: Private driver interface data - * @peer_addr: MAC address of the peer P2P client - * @config_methods: WPS Config Methods value (only one bit set) - * Returns: 0 on success, -1 on failure - * - * This function can be used to request a discovered P2P peer to - * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared - * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The - * Provision Discovery Request frame is transmitted once immediately - * and if no response is received, the frame will be sent again - * whenever the target device is discovered during device dsicovery - * (start with a p2p_find() call). Response from the peer is indicated - * with the EVENT_P2P_PROV_DISC_RESPONSE event. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr, - u16 config_methods, int join); - - /** - * p2p_sd_request - Schedule a service discovery query - * @priv: Private driver interface data - * @dst: Destination peer or %NULL to apply for all peers - * @tlvs: P2P Service Query TLV(s) - * Returns: Reference to the query or 0 on failure - * - * Response to the query is indicated with the - * EVENT_P2P_SD_RESPONSE driver event. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - u64 (*p2p_sd_request)(void *priv, const u8 *dst, - const struct wpabuf *tlvs); - - /** - * p2p_sd_cancel_request - Cancel a pending service discovery query - * @priv: Private driver interface data - * @req: Query reference from p2p_sd_request() - * Returns: 0 on success, -1 on failure - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_sd_cancel_request)(void *priv, u64 req); - - /** - * p2p_sd_response - Send response to a service discovery query - * @priv: Private driver interface data - * @freq: Frequency from EVENT_P2P_SD_REQUEST event - * @dst: Destination address from EVENT_P2P_SD_REQUEST event - * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event - * @resp_tlvs: P2P Service Response TLV(s) - * Returns: 0 on success, -1 on failure - * - * This function is called as a response to the request indicated with - * the EVENT_P2P_SD_REQUEST driver event. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_sd_response)(void *priv, int freq, const u8 *dst, - u8 dialog_token, - const struct wpabuf *resp_tlvs); - - /** - * p2p_service_update - Indicate a change in local services - * @priv: Private driver interface data - * Returns: 0 on success, -1 on failure - * - * This function needs to be called whenever there is a change in - * availability of the local services. This will increment the - * Service Update Indicator value which will be used in SD Request and - * Response frames. - * - * This function is only used if the driver implements P2P management, - * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in - * struct wpa_driver_capa. - */ - int (*p2p_service_update)(void *priv); - - /** - * p2p_reject - Reject peer device (explicitly block connections) - * @priv: Private driver interface data - * @addr: MAC address of the peer - * Returns: 0 on success, -1 on failure - */ - int (*p2p_reject)(void *priv, const u8 *addr); - - /** - * p2p_invite - Invite a P2P Device into a group - * @priv: Private driver interface data - * @peer: Device Address of the peer P2P Device - * @role: Local role in the group - * @bssid: Group BSSID or %NULL if not known - * @ssid: Group SSID - * @ssid_len: Length of ssid in octets - * @go_dev_addr: Forced GO Device Address or %NULL if none - * @persistent_group: Whether this is to reinvoke a persistent group - * Returns: 0 on success, -1 on failure - */ - int (*p2p_invite)(void *priv, const u8 *peer, int role, - const u8 *bssid, const u8 *ssid, size_t ssid_len, - const u8 *go_dev_addr, int persistent_group); - - /** * send_tdls_mgmt - for sending TDLS management packets * @priv: private driver interface data * @dst: Destination (peer) MAC address @@ -3092,15 +2891,6 @@ enum wpa_event_type { EVENT_RX_MGMT, /** - * EVENT_RX_ACTION - Action frame received - * - * This event is used to indicate when an Action frame has been - * received. Information about the received frame is included in - * union wpa_event_data::rx_action. - */ - EVENT_RX_ACTION, - - /** * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started * * This event is used to indicate when the driver has started the @@ -3247,38 +3037,6 @@ enum wpa_event_type { EVENT_STATION_LOW_ACK, /** - * EVENT_P2P_DEV_FOUND - Report a discovered P2P device - * - * This event is used only if the driver implements P2P management - * internally. Event data is stored in - * union wpa_event_data::p2p_dev_found. - */ - EVENT_P2P_DEV_FOUND, - - /** - * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request - * - * This event is used only if the driver implements P2P management - * internally. Event data is stored in - * union wpa_event_data::p2p_go_neg_req_rx. - */ - EVENT_P2P_GO_NEG_REQ_RX, - - /** - * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation - * - * This event is used only if the driver implements P2P management - * internally. Event data is stored in - * union wpa_event_data::p2p_go_neg_completed. - */ - EVENT_P2P_GO_NEG_COMPLETED, - - EVENT_P2P_PROV_DISC_REQUEST, - EVENT_P2P_PROV_DISC_RESPONSE, - EVENT_P2P_SD_REQUEST, - EVENT_P2P_SD_RESPONSE, - - /** * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore */ EVENT_IBSS_PEER_LOST, @@ -3365,17 +3123,27 @@ enum wpa_event_type { */ EVENT_DFS_NOP_FINISHED, - /* - * EVENT_SURVEY - Received survey data - * - * This event gets triggered when a driver query is issued for survey - * data and the requested data becomes available. The returned data is - * stored in struct survey_results. The results provide at most one - * survey entry for each frequency and at minimum will provide one survey - * entry for one frequency. The survey data can be os_malloc()'d and - * then os_free()'d, so the event callback must only copy data. - */ - EVENT_SURVEY + /** + * EVENT_SURVEY - Received survey data + * + * This event gets triggered when a driver query is issued for survey + * data and the requested data becomes available. The returned data is + * stored in struct survey_results. The results provide at most one + * survey entry for each frequency and at minimum will provide one + * survey entry for one frequency. The survey data can be os_malloc()'d + * and then os_free()'d, so the event callback must only copy data. + */ + EVENT_SURVEY, + + /** + * EVENT_SCAN_STARTED - Scan started + * + * This indicates that driver has started a scan operation either based + * on a request from wpa_supplicant/hostapd or from another application. + * EVENT_SCAN_RESULTS is used to indicate when the scan has been + * completed (either successfully or by getting cancelled). + */ + EVENT_SCAN_STARTED }; @@ -3743,48 +3511,17 @@ union wpa_event_data { const u8 *frame; size_t frame_len; u32 datarate; - int ssi_signal; /* dBm */ - } rx_mgmt; - /** - * struct rx_action - Data for EVENT_RX_ACTION events - */ - struct rx_action { /** - * da - Destination address of the received Action frame - */ - const u8 *da; - - /** - * sa - Source address of the received Action frame - */ - const u8 *sa; - - /** - * bssid - Address 3 of the received Action frame - */ - const u8 *bssid; - - /** - * category - Action frame category - */ - u8 category; - - /** - * data - Action frame body after category field - */ - const u8 *data; - - /** - * len - Length of data in octets + * freq - Frequency (in MHz) on which the frame was received */ - size_t len; + int freq; /** - * freq - Frequency (in MHz) on which the frame was received + * ssi_signal - Signal strength in dBm (or 0 if not available) */ - int freq; - } rx_action; + int ssi_signal; + } rx_mgmt; /** * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events @@ -3924,66 +3661,6 @@ union wpa_event_data { } low_ack; /** - * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND - */ - struct p2p_dev_found { - const u8 *addr; - const u8 *dev_addr; - const u8 *pri_dev_type; - const char *dev_name; - u16 config_methods; - u8 dev_capab; - u8 group_capab; - } p2p_dev_found; - - /** - * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX - */ - struct p2p_go_neg_req_rx { - const u8 *src; - u16 dev_passwd_id; - } p2p_go_neg_req_rx; - - /** - * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED - */ - struct p2p_go_neg_completed { - struct p2p_go_neg_results *res; - } p2p_go_neg_completed; - - struct p2p_prov_disc_req { - const u8 *peer; - u16 config_methods; - const u8 *dev_addr; - const u8 *pri_dev_type; - const char *dev_name; - u16 supp_config_methods; - u8 dev_capab; - u8 group_capab; - } p2p_prov_disc_req; - - struct p2p_prov_disc_resp { - const u8 *peer; - u16 config_methods; - } p2p_prov_disc_resp; - - struct p2p_sd_req { - int freq; - const u8 *sa; - u8 dialog_token; - u16 update_indic; - const u8 *tlvs; - size_t tlvs_len; - } p2p_sd_req; - - struct p2p_sd_resp { - const u8 *sa; - u16 update_indic; - const u8 *tlvs; - size_t tlvs_len; - } p2p_sd_resp; - - /** * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST */ struct ibss_peer_lost { @@ -4143,4 +3820,7 @@ void wpa_scan_results_free(struct wpa_scan_results *res); /* Convert wpa_event_type to a string for logging */ const char * event_to_string(enum wpa_event_type event); +/* NULL terminated array of linked in driver wrappers */ +extern struct wpa_driver_ops *wpa_drivers[]; + #endif /* DRIVER_H */ diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index 7d301f79..23a4e2b9 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -806,16 +806,10 @@ static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf, drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); break; case WLAN_FC_STYPE_ACTION: - if (&mgmt->u.action.category > buf + len) - break; os_memset(&event, 0, sizeof(event)); - event.rx_action.da = mgmt->da; - event.rx_action.sa = mgmt->sa; - event.rx_action.bssid = mgmt->bssid; - event.rx_action.category = mgmt->u.action.category; - event.rx_action.data = &mgmt->u.action.category; - event.rx_action.len = buf + len - event.rx_action.data; - wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event); + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); break; case WLAN_FC_STYPE_AUTH: if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth)) @@ -954,16 +948,10 @@ static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf, switch (stype) { case WLAN_FC_STYPE_ACTION: - if (&mgmt->u.action.category > buf + len) - break; os_memset(&event, 0, sizeof(event)); - event.rx_action.da = mgmt->da; - event.rx_action.sa = mgmt->sa; - event.rx_action.bssid = mgmt->bssid; - event.rx_action.category = mgmt->u.action.category; - event.rx_action.data = &mgmt->u.action.category; - event.rx_action.len = buf + len - event.rx_action.data; - wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event); + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); break; default: break; diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index fb6402da..7f5e2314 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -1110,9 +1110,9 @@ wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) return -1; - privacy = !(params->pairwise_suite == CIPHER_NONE && - params->group_suite == CIPHER_NONE && - params->key_mgmt_suite == KEY_MGMT_NONE && + privacy = !(params->pairwise_suite == WPA_CIPHER_NONE && + params->group_suite == WPA_CIPHER_NONE && + params->key_mgmt_suite == WPA_KEY_MGMT_NONE && params->wpa_ie_len == 0); wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 8d1d22eb..64bdddb2 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -49,7 +49,6 @@ const char * event_to_string(enum wpa_event_type event) E2S(TX_STATUS); E2S(RX_FROM_UNKNOWN); E2S(RX_MGMT); - E2S(RX_ACTION); E2S(REMAIN_ON_CHANNEL); E2S(CANCEL_REMAIN_ON_CHANNEL); E2S(MLME_RX); @@ -65,13 +64,6 @@ const char * event_to_string(enum wpa_event_type event) E2S(UNPROT_DEAUTH); E2S(UNPROT_DISASSOC); E2S(STATION_LOW_ACK); - E2S(P2P_DEV_FOUND); - E2S(P2P_GO_NEG_REQ_RX); - E2S(P2P_GO_NEG_COMPLETED); - E2S(P2P_PROV_DISC_REQUEST); - E2S(P2P_PROV_DISC_RESPONSE); - E2S(P2P_SD_REQUEST); - E2S(P2P_SD_RESPONSE); E2S(IBSS_PEER_LOST); E2S(DRIVER_GTK_REKEY); E2S(SCHED_SCAN_STOPPED); @@ -85,6 +77,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(DFS_CAC_ABORTED); E2S(DFS_NOP_FINISHED); E2S(SURVEY); + E2S(SCAN_STARTED); } return "UNKNOWN"; diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c index 09308347..1635c1fb 100644 --- a/src/drivers/driver_madwifi.c +++ b/src/drivers/driver_madwifi.c @@ -1,5 +1,5 @@ /* - * WPA Supplicant - driver interaction with MADWIFI 802.11 driver + * hostapd - driver interaction with MADWIFI 802.11 driver * Copyright (c) 2004, Sam Leffler <sam@errno.com> * Copyright (c) 2004, Video54 Technologies * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> @@ -7,10 +7,9 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. * - * While this driver wrapper supports both AP (hostapd) and station - * (wpa_supplicant) operations, the station side is deprecated and - * driver_wext.c should be used instead. This driver wrapper should only be - * used with hostapd for AP mode functionality. + * This driver wrapper is only for hostapd AP mode functionality. Station + * (wpa_supplicant) operations with madwifi are supported by the driver_wext.c + * wrapper. */ #include "includes.h" diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 4656c1b7..4953af6a 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -1074,8 +1074,8 @@ wpa_driver_ndis_associate(void *priv, /* Try to continue anyway */ } - if (params->key_mgmt_suite == KEY_MGMT_NONE || - params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) { + if (params->key_mgmt_suite == WPA_KEY_MGMT_NONE || + params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { /* Re-set WEP keys if static WEP configuration is used. */ int i; for (i = 0; i < 4; i++) { @@ -1102,12 +1102,12 @@ wpa_driver_ndis_associate(void *priv, priv_mode = Ndis802_11PrivFilterAcceptAll; } else if (params->wpa_ie[0] == WLAN_EID_RSN) { priv_mode = Ndis802_11PrivFilter8021xWEP; - if (params->key_mgmt_suite == KEY_MGMT_PSK) + if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK) auth_mode = Ndis802_11AuthModeWPA2PSK; else auth_mode = Ndis802_11AuthModeWPA2; #ifdef CONFIG_WPS - } else if (params->key_mgmt_suite == KEY_MGMT_WPS) { + } else if (params->key_mgmt_suite == WPA_KEY_MGMT_WPS) { auth_mode = Ndis802_11AuthModeOpen; priv_mode = Ndis802_11PrivFilterAcceptAll; if (params->wps == WPS_MODE_PRIVACY) { @@ -1129,35 +1129,35 @@ wpa_driver_ndis_associate(void *priv, #endif /* CONFIG_WPS */ } else { priv_mode = Ndis802_11PrivFilter8021xWEP; - if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE) + if (params->key_mgmt_suite == WPA_KEY_MGMT_WPA_NONE) auth_mode = Ndis802_11AuthModeWPANone; - else if (params->key_mgmt_suite == KEY_MGMT_PSK) + else if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK) auth_mode = Ndis802_11AuthModeWPAPSK; else auth_mode = Ndis802_11AuthModeWPA; } switch (params->pairwise_suite) { - case CIPHER_CCMP: + case WPA_CIPHER_CCMP: encr = Ndis802_11Encryption3Enabled; break; - case CIPHER_TKIP: + case WPA_CIPHER_TKIP: encr = Ndis802_11Encryption2Enabled; break; - case CIPHER_WEP40: - case CIPHER_WEP104: + case WPA_CIPHER_WEP40: + case WPA_CIPHER_WEP104: encr = Ndis802_11Encryption1Enabled; break; - case CIPHER_NONE: + case WPA_CIPHER_NONE: #ifdef CONFIG_WPS if (params->wps == WPS_MODE_PRIVACY) { encr = Ndis802_11Encryption1Enabled; break; } #endif /* CONFIG_WPS */ - if (params->group_suite == CIPHER_CCMP) + if (params->group_suite == WPA_CIPHER_CCMP) encr = Ndis802_11Encryption3Enabled; - else if (params->group_suite == CIPHER_TKIP) + else if (params->group_suite == WPA_CIPHER_TKIP) encr = Ndis802_11Encryption2Enabled; else encr = Ndis802_11EncryptionDisabled; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 42dddf04..fce6efde 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1,6 +1,6 @@ /* * Driver interaction with Linux nl80211/cfg80211 - * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> * Copyright (c) 2003-2004, Instant802 Networks, Inc. * Copyright (c) 2005-2006, Devicescape Software, Inc. * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> @@ -300,7 +300,6 @@ struct wpa_driver_nl80211_data { unsigned int hostapd:1; unsigned int start_mode_ap:1; unsigned int start_iface_up:1; - unsigned int channel_switch_supported:1; u64 remain_on_chan_cookie; u64 send_action_cookie; @@ -497,6 +496,11 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) C2S(NL80211_CMD_FT_EVENT) C2S(NL80211_CMD_CRIT_PROTOCOL_START) C2S(NL80211_CMD_CRIT_PROTOCOL_STOP) + C2S(NL80211_CMD_GET_COALESCE) + C2S(NL80211_CMD_SET_COALESCE) + C2S(NL80211_CMD_CHANNEL_SWITCH) + C2S(NL80211_CMD_VENDOR) + C2S(NL80211_CMD_SET_QOS_MAP) default: return "NL80211_CMD_UNKNOWN"; } @@ -1045,49 +1049,55 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) } -static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, - char *buf, size_t len, int del) +static void wpa_driver_nl80211_event_newlink( + struct wpa_driver_nl80211_data *drv, char *ifname) { union wpa_event_data event; + if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { + if (if_nametoindex(drv->first_bss->ifname) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK", + drv->first_bss->ifname); + return; + } + if (!drv->if_removed) + return; + wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event", + drv->first_bss->ifname); + drv->if_removed = 0; + } + os_memset(&event, 0, sizeof(event)); - if (len > sizeof(event.interface_status.ifname)) - len = sizeof(event.interface_status.ifname) - 1; - os_memcpy(event.interface_status.ifname, buf, len); - event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : - EVENT_INTERFACE_ADDED; - - wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", - del ? "DEL" : "NEW", - event.interface_status.ifname, - del ? "removed" : "added"); - - if (os_strcmp(drv->first_bss->ifname, event.interface_status.ifname) == - 0) { - if (del) { - if (drv->if_removed) { - wpa_printf(MSG_DEBUG, "nl80211: if_removed " - "already set - ignore event"); - return; - } - drv->if_removed = 1; - } else { - if (if_nametoindex(drv->first_bss->ifname) == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Interface %s " - "does not exist - ignore " - "RTM_NEWLINK", - drv->first_bss->ifname); - return; - } - if (!drv->if_removed) { - wpa_printf(MSG_DEBUG, "nl80211: if_removed " - "already cleared - ignore event"); - return; - } - drv->if_removed = 0; + os_strlcpy(event.interface_status.ifname, ifname, + sizeof(event.interface_status.ifname)); + event.interface_status.ievent = EVENT_INTERFACE_ADDED; + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); +} + + +static void wpa_driver_nl80211_event_dellink( + struct wpa_driver_nl80211_data *drv, char *ifname) +{ + union wpa_event_data event; + + if (os_strcmp(drv->first_bss->ifname, ifname) == 0) { + if (drv->if_removed) { + wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s", + ifname); + return; } + wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1", + ifname); + drv->if_removed = 1; + } else { + wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed", + ifname); } + os_memset(&event, 0, sizeof(event)); + os_strlcpy(event.interface_status.ifname, ifname, + sizeof(event.interface_status.ifname)); + event.interface_status.ievent = EVENT_INTERFACE_REMOVED; wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); } @@ -1154,21 +1164,57 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, { struct nl80211_global *global = ctx; struct wpa_driver_nl80211_data *drv; - int attrlen, rta_len; + int attrlen; struct rtattr *attr; u32 brid = 0; char namebuf[IFNAMSIZ]; + char ifname[IFNAMSIZ + 1]; + char extra[100], *pos, *end; drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign " - "ifindex %d", ifi->ifi_index); + wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d", + ifi->ifi_index); return; } - wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " - "(%s%s%s%s)", - drv->operstate, ifi->ifi_flags, + extra[0] = '\0'; + pos = extra; + end = pos + sizeof(extra); + ifname[0] = '\0'; + + attrlen = len; + attr = (struct rtattr *) buf; + while (RTA_OK(attr, attrlen)) { + switch (attr->rta_type) { + case IFLA_IFNAME: + if (RTA_PAYLOAD(attr) >= IFNAMSIZ) + break; + os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); + ifname[RTA_PAYLOAD(attr)] = '\0'; + break; + case IFLA_MASTER: + brid = nla_get_u32((struct nlattr *) attr); + pos += os_snprintf(pos, end - pos, " master=%u", brid); + break; + case IFLA_WIRELESS: + pos += os_snprintf(pos, end - pos, " wext"); + break; + case IFLA_OPERSTATE: + pos += os_snprintf(pos, end - pos, " operstate=%u", + nla_get_u32((struct nlattr *) attr)); + break; + case IFLA_LINKMODE: + pos += os_snprintf(pos, end - pos, " linkmode=%u", + nla_get_u32((struct nlattr *) attr)); + break; + } + attr = RTA_NEXT(attr, attrlen); + } + extra[sizeof(extra) - 1] = '\0'; + + wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)", + ifi->ifi_index, ifname, extra, ifi->ifi_flags, (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", @@ -1225,24 +1271,15 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, */ if (drv->operstate == 1 && (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && - !(ifi->ifi_flags & IFF_RUNNING)) + !(ifi->ifi_flags & IFF_RUNNING)) { + wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate"); netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, IF_OPER_UP); - - attrlen = len; - attr = (struct rtattr *) buf; - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_nl80211_event_link( - drv, - ((char *) attr) + rta_len, - attr->rta_len - rta_len, 0); - } else if (attr->rta_type == IFLA_MASTER) - brid = nla_get_u32((struct nlattr *) attr); - attr = RTA_NEXT(attr, attrlen); } + if (ifname[0]) + wpa_driver_nl80211_event_newlink(drv, ifname); + if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been added to bridge */ if_indextoname(brid, namebuf); @@ -1259,32 +1296,40 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, { struct nl80211_global *global = ctx; struct wpa_driver_nl80211_data *drv; - int attrlen, rta_len; + int attrlen; struct rtattr *attr; u32 brid = 0; + char ifname[IFNAMSIZ + 1]; drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for " - "foreign ifindex %d", ifi->ifi_index); + wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d", + ifi->ifi_index); return; } + ifname[0] = '\0'; + attrlen = len; attr = (struct rtattr *) buf; - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_IFNAME) { - wpa_driver_nl80211_event_link( - drv, - ((char *) attr) + rta_len, - attr->rta_len - rta_len, 1); - } else if (attr->rta_type == IFLA_MASTER) + switch (attr->rta_type) { + case IFLA_IFNAME: + if (RTA_PAYLOAD(attr) >= IFNAMSIZ) + break; + os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); + ifname[RTA_PAYLOAD(attr)] = '\0'; + break; + case IFLA_MASTER: brid = nla_get_u32((struct nlattr *) attr); + break; + } attr = RTA_NEXT(attr, attrlen); } + if (ifname[0]) + wpa_driver_nl80211_event_dellink(drv, ifname); + if (ifi->ifi_family == AF_BRIDGE && brid) { /* device has been removed from bridge */ char namebuf[IFNAMSIZ]; @@ -1602,7 +1647,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_MSGDUMP, "nl80211: Frame event"); mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24) { - wpa_printf(MSG_DEBUG, "nl80211: Too short action frame"); + wpa_printf(MSG_DEBUG, "nl80211: Too short management frame"); return; } @@ -1614,26 +1659,16 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, os_memset(&event, 0, sizeof(event)); if (freq) { - event.rx_action.freq = nla_get_u32(freq); - rx_freq = drv->last_mgmt_freq = event.rx_action.freq; + event.rx_mgmt.freq = nla_get_u32(freq); + rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq; } wpa_printf(MSG_DEBUG, "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u", rx_freq, ssi_signal, stype, (unsigned int) len); - if (stype == WLAN_FC_STYPE_ACTION) { - event.rx_action.da = mgmt->da; - event.rx_action.sa = mgmt->sa; - event.rx_action.bssid = mgmt->bssid; - event.rx_action.category = mgmt->u.action.category; - event.rx_action.data = &mgmt->u.action.category + 1; - event.rx_action.len = frame + len - event.rx_action.data; - wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); - } else { - event.rx_mgmt.frame = frame; - event.rx_mgmt.frame_len = len; - event.rx_mgmt.ssi_signal = ssi_signal; - wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); - } + event.rx_mgmt.frame = frame; + event.rx_mgmt.frame_len = len; + event.rx_mgmt.ssi_signal = ssi_signal; + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } @@ -2037,21 +2072,36 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, &info->ssids[info->num_ssids]; s->ssid = nla_data(nl); s->ssid_len = nla_len(nl); + wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'", + wpa_ssid_txt(s->ssid, s->ssid_len)); info->num_ssids++; if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) break; } } if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { + char msg[200], *pos, *end; + int res; + + pos = msg; + end = pos + sizeof(msg); + *pos = '\0'; + nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) { freqs[num_freqs] = nla_get_u32(nl); + res = os_snprintf(pos, end - pos, " %d", + freqs[num_freqs]); + if (res > 0 && end - pos > res) + pos += res; num_freqs++; if (num_freqs == MAX_REPORT_FREQS - 1) break; } info->freqs = freqs; info->num_freqs = num_freqs; + wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s", + msg); } wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); } @@ -2666,6 +2716,48 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, } +static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + u32 vendor_id, subcmd, wiphy = 0; + int wiphy_idx; + u8 *data = NULL; + size_t len = 0; + + if (!tb[NL80211_ATTR_VENDOR_ID] || + !tb[NL80211_ATTR_VENDOR_SUBCMD]) + return; + + vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]); + subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]); + + if (tb[NL80211_ATTR_WIPHY]) + wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + + wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u", + wiphy, vendor_id, subcmd); + + if (tb[NL80211_ATTR_VENDOR_DATA]) { + data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]); + len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]); + wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len); + } + + wiphy_idx = nl80211_get_wiphy_index(drv->first_bss); + if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)", + wiphy, wiphy_idx); + return; + } + + switch (vendor_id) { + default: + wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); + break; + } +} + + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -2687,6 +2779,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_TRIGGER_SCAN: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger"); drv->scan_state = SCAN_STARTED; + wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); break; case NL80211_CMD_START_SCHED_SCAN: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started"); @@ -2838,6 +2931,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_STOP_AP: nl80211_stop_ap(drv, tb); break; + case NL80211_CMD_VENDOR: + nl80211_vendor_event(drv, tb); + break; default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); @@ -3105,6 +3201,7 @@ struct wiphy_info_data { unsigned int p2p_client_supported:1; unsigned int p2p_concurrent:1; unsigned int channel_switch_supported:1; + unsigned int set_qos_map_supported:1; }; @@ -3265,6 +3362,65 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info, case NL80211_CMD_CHANNEL_SWITCH: info->channel_switch_supported = 1; break; + case NL80211_CMD_SET_QOS_MAP: + info->set_qos_map_supported = 1; + break; + } + } +} + + +static void wiphy_info_cipher_suites(struct wiphy_info_data *info, + struct nlattr *tb) +{ + int i, num; + u32 *ciphers; + + if (tb == NULL) + return; + + num = nla_len(tb) / sizeof(u32); + ciphers = nla_data(tb); + for (i = 0; i < num; i++) { + u32 c = ciphers[i]; + + wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d", + c >> 24, (c >> 16) & 0xff, + (c >> 8) & 0xff, c & 0xff); + switch (c) { + case WLAN_CIPHER_SUITE_CCMP_256: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256; + break; + case WLAN_CIPHER_SUITE_CCMP: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP; + break; + case WLAN_CIPHER_SUITE_GCMP: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP; + break; + case WLAN_CIPHER_SUITE_TKIP: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP; + break; + case WLAN_CIPHER_SUITE_WEP104: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104; + break; + case WLAN_CIPHER_SUITE_WEP40: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256; + break; } } } @@ -3369,6 +3525,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]); wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]); wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]); + wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]); if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " @@ -3421,6 +3578,38 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) } } + if (tb[NL80211_ATTR_VENDOR_DATA]) { + struct nlattr *nl; + int rem; + + nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) { + struct nl80211_vendor_cmd_info *vinfo; + if (nla_len(nl) != sizeof(vinfo)) { + wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); + continue; + } + vinfo = nla_data(nl); + wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", + vinfo->vendor_id, vinfo->subcmd); + } + } + + if (tb[NL80211_ATTR_VENDOR_EVENTS]) { + struct nlattr *nl; + int rem; + + nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) { + struct nl80211_vendor_cmd_info *vinfo; + if (nla_len(nl) != sizeof(vinfo)) { + wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); + continue; + } + vinfo = nla_data(nl); + wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u", + vinfo->vendor_id, vinfo->subcmd); + } + } + return NL_SKIP; } @@ -3479,6 +3668,9 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, if (!drv->capa.max_remain_on_chan) drv->capa.max_remain_on_chan = 5000; + if (info->channel_switch_supported) + drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA; + return 0; nla_put_failure: nlmsg_free(msg); @@ -3496,15 +3688,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) return -1; drv->has_capability = 1; - /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; - drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | - WPA_DRIVER_CAPA_ENC_WEP104 | - WPA_DRIVER_CAPA_ENC_TKIP | - WPA_DRIVER_CAPA_ENC_CCMP; drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; @@ -3526,7 +3713,8 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->device_ap_sme = info.device_ap_sme; drv->poll_command_supported = info.poll_command_supported; drv->data_tx_status = info.data_tx_status; - drv->channel_switch_supported = info.channel_switch_supported; + if (info.set_qos_map_supported) + drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING; /* * If poll command and tx status are supported, mac80211 is new enough @@ -3652,6 +3840,16 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) /* Continue without regulatory events */ } + ret = nl_get_multicast_id(global, "nl80211", "vendor"); + if (ret >= 0) + ret = nl_socket_add_membership(global->nl_event, ret); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " + "membership for vendor events: %d (%s)", + ret, strerror(-ret)); + /* Continue without vendor events */ + } + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, @@ -3912,15 +4110,16 @@ static int nl80211_register_frame(struct i802_bss *bss, struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; int ret = -1; + char buf[30]; msg = nlmsg_alloc(); if (!msg) return -1; - wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p", - type, nl_handle); - wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match", - match, match_len); + buf[0] = '\0'; + wpa_snprintf_hex(buf, sizeof(buf), match, match_len); + wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p match=%s", + type, nl_handle, buf); nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); @@ -3985,6 +4184,7 @@ static int nl80211_register_action_frame(struct i802_bss *bss, static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) { struct wpa_driver_nl80211_data *drv = bss->drv; + int ret = 0; if (nl80211_alloc_mgmt_handle(bss)) return -1; @@ -4001,65 +4201,65 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) #ifdef CONFIG_INTERWORKING /* QoS Map Configure */ if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0) - return -1; + ret = -1; #endif /* CONFIG_INTERWORKING */ #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) /* GAS Initial Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0) - return -1; + ret = -1; /* GAS Initial Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0) - return -1; + ret = -1; /* GAS Comeback Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0) - return -1; + ret = -1; /* GAS Comeback Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0) - return -1; + ret = -1; #endif /* CONFIG_P2P || CONFIG_INTERWORKING */ #ifdef CONFIG_P2P /* P2P Public Action */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x09\x50\x6f\x9a\x09", 6) < 0) - return -1; + ret = -1; /* P2P Action */ if (nl80211_register_action_frame(bss, (u8 *) "\x7f\x50\x6f\x9a\x09", 5) < 0) - return -1; + ret = -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_IEEE80211W /* SA Query Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0) - return -1; + ret = -1; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_TDLS if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) { /* TDLS Discovery Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) < 0) - return -1; + ret = -1; } #endif /* CONFIG_TDLS */ /* FT Action frames */ if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) - return -1; + ret = -1; else drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; /* WNM - BSS Transition Management Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0) - return -1; + ret = -1; /* WNM-Sleep Mode Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0) - return -1; + ret = -1; nl80211_mgmt_handle_register_eloop(bss); - return 0; + return ret; } @@ -4521,6 +4721,12 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd, params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; + if (params->only_new_results) { + wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH"); + NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, + NL80211_SCAN_FLAG_FLUSH); + } + return msg; fail: @@ -4931,7 +5137,8 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does * not use frequency as a separate key in the BSS table, so filter out * duplicated entries. Prefer associated BSS entry in such a case in - * order to get the correct frequency into the BSS table. + * order to get the correct frequency into the BSS table. Similarly, + * prefer newer entries over older. */ for (i = 0; i < res->num; i++) { const u8 *s1, *s2; @@ -4949,8 +5156,9 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result " "for " MACSTR, MAC2STR(r->bssid)); - if ((r->flags & WPA_SCAN_ASSOCIATED) && - !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) { + if (((r->flags & WPA_SCAN_ASSOCIATED) && + !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) || + r->age < res->res[i]->age) { os_free(res->res[i]); res->res[i] = r; } else @@ -5116,6 +5324,95 @@ static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv) } +static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len) +{ + switch (alg) { + case WPA_ALG_WEP: + if (key_len == 5) + return WLAN_CIPHER_SUITE_WEP40; + return WLAN_CIPHER_SUITE_WEP104; + case WPA_ALG_TKIP: + return WLAN_CIPHER_SUITE_TKIP; + case WPA_ALG_CCMP: + return WLAN_CIPHER_SUITE_CCMP; + case WPA_ALG_GCMP: + return WLAN_CIPHER_SUITE_GCMP; + case WPA_ALG_CCMP_256: + return WLAN_CIPHER_SUITE_CCMP_256; + case WPA_ALG_GCMP_256: + return WLAN_CIPHER_SUITE_GCMP_256; + case WPA_ALG_IGTK: + return WLAN_CIPHER_SUITE_AES_CMAC; + case WPA_ALG_BIP_GMAC_128: + return WLAN_CIPHER_SUITE_BIP_GMAC_128; + case WPA_ALG_BIP_GMAC_256: + return WLAN_CIPHER_SUITE_BIP_GMAC_256; + case WPA_ALG_BIP_CMAC_256: + return WLAN_CIPHER_SUITE_BIP_CMAC_256; + case WPA_ALG_SMS4: + return WLAN_CIPHER_SUITE_SMS4; + case WPA_ALG_KRK: + return WLAN_CIPHER_SUITE_KRK; + case WPA_ALG_NONE: + case WPA_ALG_PMK: + wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d", + alg); + return 0; + } + + wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d", + alg); + return 0; +} + + +static u32 wpa_cipher_to_cipher_suite(unsigned int cipher) +{ + switch (cipher) { + case WPA_CIPHER_CCMP_256: + return WLAN_CIPHER_SUITE_CCMP_256; + case WPA_CIPHER_GCMP_256: + return WLAN_CIPHER_SUITE_GCMP_256; + case WPA_CIPHER_CCMP: + return WLAN_CIPHER_SUITE_CCMP; + case WPA_CIPHER_GCMP: + return WLAN_CIPHER_SUITE_GCMP; + case WPA_CIPHER_TKIP: + return WLAN_CIPHER_SUITE_TKIP; + case WPA_CIPHER_WEP104: + return WLAN_CIPHER_SUITE_WEP104; + case WPA_CIPHER_WEP40: + return WLAN_CIPHER_SUITE_WEP40; + } + + return 0; +} + + +static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[], + int max_suites) +{ + int num_suites = 0; + + if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256) + suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256; + if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256) + suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256; + if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; + if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP) + suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP; + if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP) + suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; + if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; + if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40) + suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; + + return num_suites; +} + + static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, @@ -5153,45 +5450,8 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, } else { nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY); NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); - switch (alg) { - case WPA_ALG_WEP: - if (key_len == 5) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP40); - else - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP104); - break; - case WPA_ALG_TKIP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_TKIP); - break; - case WPA_ALG_CCMP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_CCMP); - break; - case WPA_ALG_GCMP: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_GCMP); - break; - case WPA_ALG_IGTK: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_AES_CMAC); - break; - case WPA_ALG_SMS4: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_SMS4); - break; - case WPA_ALG_KRK: - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - WLAN_CIPHER_SUITE_KRK); - break; - default: - wpa_printf(MSG_ERROR, "%s: Unsupported encryption " - "algorithm %d", __func__, alg); - nlmsg_free(msg); - return -1; - } + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, + wpa_alg_to_cipher_suite(alg, key_len)); } if (seq && seq_len) @@ -5296,33 +5556,8 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); - switch (alg) { - case WPA_ALG_WEP: - if (key_len == 5) - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP40); - else - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_WEP104); - break; - case WPA_ALG_TKIP: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); - break; - case WPA_ALG_CCMP: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); - break; - case WPA_ALG_GCMP: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP); - break; - case WPA_ALG_IGTK: - NLA_PUT_U32(msg, NL80211_KEY_CIPHER, - WLAN_CIPHER_SUITE_AES_CMAC); - break; - default: - wpa_printf(MSG_ERROR, "%s: Unsupported encryption " - "algorithm %d", __func__, alg); - return -1; - } + NLA_PUT_U32(msg, NL80211_KEY_CIPHER, + wpa_alg_to_cipher_suite(alg, key_len)); if (seq && seq_len) NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq); @@ -5784,10 +6019,8 @@ static void phy_info_freq(struct hostapd_hw_modes *mode, if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) chan->flag |= HOSTAPD_CHAN_DISABLED; - if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) - chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) - chan->flag |= HOSTAPD_CHAN_NO_IBSS; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) + chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS; if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) chan->flag |= HOSTAPD_CHAN_RADAR; @@ -5816,8 +6049,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info, static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 }, @@ -6113,24 +6345,11 @@ static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, } -static void nl80211_reg_rule_max_eirp(struct nlattr *tb[], +static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp, struct phy_info_arg *results) { - u32 start, end, max_eirp; u16 m; - if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || - tb[NL80211_ATTR_POWER_RULE_MAX_EIRP] == NULL) - return; - - start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; - end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; - max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100; - - wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u mBm", - start, end, max_eirp); - for (m = 0; m < *results->num_modes; m++) { int c; struct hostapd_hw_modes *mode = &results->modes[m]; @@ -6145,26 +6364,11 @@ static void nl80211_reg_rule_max_eirp(struct nlattr *tb[], } -static void nl80211_reg_rule_ht40(struct nlattr *tb[], +static void nl80211_reg_rule_ht40(u32 start, u32 end, struct phy_info_arg *results) { - u32 start, end, max_bw; u16 m; - if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || - tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) - return; - - start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; - end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; - max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; - - wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz", - start, end, max_bw); - if (max_bw < 40) - return; - for (m = 0; m < *results->num_modes; m++) { if (!(results->modes[m].ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) @@ -6285,10 +6489,26 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg) nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) { + u32 start, end, max_eirp = 0, max_bw = 0; nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_rule), nla_len(nl_rule), reg_policy); - nl80211_reg_rule_ht40(tb_rule, results); - nl80211_reg_rule_max_eirp(tb_rule, results); + if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL || + tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL) + continue; + start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000; + end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000; + if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) + max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100; + if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) + max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; + + wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm", + start, end, max_bw, max_eirp); + if (max_bw >= 40) + nl80211_reg_rule_ht40(start, end, results); + if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) + nl80211_reg_rule_max_eirp(start, end, max_eirp, + results); } nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) @@ -6648,7 +6868,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, int beacon_set; int ifindex = if_nametoindex(bss->ifname); int num_suites; - u32 suites[10]; + u32 suites[10], suite; u32 ver; beacon_set = bss->beacon_set; @@ -6743,17 +6963,8 @@ static int wpa_driver_nl80211_set_ap(void *priv, wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x", params->pairwise_ciphers); - num_suites = 0; - if (params->pairwise_ciphers & WPA_CIPHER_CCMP) - suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP; - if (params->pairwise_ciphers & WPA_CIPHER_GCMP) - suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP; - if (params->pairwise_ciphers & WPA_CIPHER_TKIP) - suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP; - if (params->pairwise_ciphers & WPA_CIPHER_WEP104) - suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104; - if (params->pairwise_ciphers & WPA_CIPHER_WEP40) - suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40; + num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers, + suites, ARRAY_SIZE(suites)); if (num_suites) { NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, num_suites * sizeof(u32), suites); @@ -6761,28 +6972,9 @@ static int wpa_driver_nl80211_set_ap(void *priv, wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x", params->group_cipher); - switch (params->group_cipher) { - case WPA_CIPHER_CCMP: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_CCMP); - break; - case WPA_CIPHER_GCMP: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_GCMP); - break; - case WPA_CIPHER_TKIP: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_TKIP); - break; - case WPA_CIPHER_WEP104: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_WEP104); - break; - case WPA_CIPHER_WEP40: - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - WLAN_CIPHER_SUITE_WEP40); - break; - } + suite = wpa_cipher_to_cipher_suite(params->group_cipher); + if (suite) + NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite); if (params->beacon_ies) { wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies", @@ -7977,10 +8169,10 @@ retry: NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK || - params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 || - params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) { + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK || + params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) { wpa_printf(MSG_DEBUG, " * control port"); NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); } @@ -8018,40 +8210,32 @@ nla_put_failure: } -static int wpa_driver_nl80211_try_connect( - struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) +static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params, + struct nl_msg *msg) { - struct nl_msg *msg; - enum nl80211_auth_type type; - int ret = 0; - int algs; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); - nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (params->bssid) { wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, MAC2STR(params->bssid)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); } + if (params->freq) { wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); drv->assoc_freq = params->freq; } else drv->assoc_freq = 0; + if (params->bg_scan_period >= 0) { wpa_printf(MSG_DEBUG, " * bg scan period=%d", params->bg_scan_period); NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD, params->bg_scan_period); } + if (params->ssid) { wpa_hexdump_ascii(MSG_DEBUG, " * SSID", params->ssid, params->ssid_len); @@ -8062,39 +8246,12 @@ static int wpa_driver_nl80211_try_connect( os_memcpy(drv->ssid, params->ssid, params->ssid_len); drv->ssid_len = params->ssid_len; } + wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); if (params->wpa_ie) NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie); - algs = 0; - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - algs++; - if (params->auth_alg & WPA_AUTH_ALG_SHARED) - algs++; - if (params->auth_alg & WPA_AUTH_ALG_LEAP) - algs++; - if (algs > 1) { - wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " - "selection"); - goto skip_auth_type; - } - - if (params->auth_alg & WPA_AUTH_ALG_OPEN) - type = NL80211_AUTHTYPE_OPEN_SYSTEM; - else if (params->auth_alg & WPA_AUTH_ALG_SHARED) - type = NL80211_AUTHTYPE_SHARED_KEY; - else if (params->auth_alg & WPA_AUTH_ALG_LEAP) - type = NL80211_AUTHTYPE_NETWORK_EAP; - else if (params->auth_alg & WPA_AUTH_ALG_FT) - type = NL80211_AUTHTYPE_FT; - else - goto nla_put_failure; - - wpa_printf(MSG_DEBUG, " * Auth Type %d", type); - NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); - -skip_auth_type: if (params->wpa_proto) { enum nl80211_wpa_versions ver = 0; @@ -8107,81 +8264,39 @@ skip_auth_type: NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); } - if (params->pairwise_suite != CIPHER_NONE) { - int cipher; - - switch (params->pairwise_suite) { - case CIPHER_SMS4: - cipher = WLAN_CIPHER_SUITE_SMS4; - break; - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } + if (params->pairwise_suite != WPA_CIPHER_NONE) { + u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite); + wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); } - if (params->group_suite != CIPHER_NONE) { - int cipher; - - switch (params->group_suite) { - case CIPHER_SMS4: - cipher = WLAN_CIPHER_SUITE_SMS4; - break; - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } + if (params->group_suite != WPA_CIPHER_NONE) { + u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite); + wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); } - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK || - params->key_mgmt_suite == KEY_MGMT_FT_802_1X || - params->key_mgmt_suite == KEY_MGMT_FT_PSK || - params->key_mgmt_suite == KEY_MGMT_CCKM) { + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK || + params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK || + params->key_mgmt_suite == WPA_KEY_MGMT_CCKM) { int mgmt = WLAN_AKM_SUITE_PSK; switch (params->key_mgmt_suite) { - case KEY_MGMT_CCKM: + case WPA_KEY_MGMT_CCKM: mgmt = WLAN_AKM_SUITE_CCKM; break; - case KEY_MGMT_802_1X: + case WPA_KEY_MGMT_IEEE8021X: mgmt = WLAN_AKM_SUITE_8021X; break; - case KEY_MGMT_FT_802_1X: + case WPA_KEY_MGMT_FT_IEEE8021X: mgmt = WLAN_AKM_SUITE_FT_8021X; break; - case KEY_MGMT_FT_PSK: + case WPA_KEY_MGMT_FT_PSK: mgmt = WLAN_AKM_SUITE_FT_PSK; break; - case KEY_MGMT_PSK: + case WPA_KEY_MGMT_PSK: default: mgmt = WLAN_AKM_SUITE_PSK; break; @@ -8189,10 +8304,10 @@ skip_auth_type: NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); } -#ifdef CONFIG_IEEE80211W + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); + if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); -#endif /* CONFIG_IEEE80211W */ if (params->disable_ht) NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT); @@ -8218,6 +8333,63 @@ skip_auth_type: } #endif /* CONFIG_VHT_OVERRIDES */ + if (params->p2p) + wpa_printf(MSG_DEBUG, " * P2P group"); + + return 0; +nla_put_failure: + return -1; +} + + +static int wpa_driver_nl80211_try_connect( + struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + struct nl_msg *msg; + enum nl80211_auth_type type; + int ret; + int algs; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); + nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT); + + ret = nl80211_connect_common(drv, params, msg); + if (ret) + goto nla_put_failure; + + algs = 0; + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + algs++; + if (params->auth_alg & WPA_AUTH_ALG_SHARED) + algs++; + if (params->auth_alg & WPA_AUTH_ALG_LEAP) + algs++; + if (algs > 1) { + wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " + "selection"); + goto skip_auth_type; + } + + if (params->auth_alg & WPA_AUTH_ALG_OPEN) + type = NL80211_AUTHTYPE_OPEN_SYSTEM; + else if (params->auth_alg & WPA_AUTH_ALG_SHARED) + type = NL80211_AUTHTYPE_SHARED_KEY; + else if (params->auth_alg & WPA_AUTH_ALG_LEAP) + type = NL80211_AUTHTYPE_NETWORK_EAP; + else if (params->auth_alg & WPA_AUTH_ALG_FT) + type = NL80211_AUTHTYPE_FT; + else + goto nla_put_failure; + + wpa_printf(MSG_DEBUG, " * Auth Type %d", type); + NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); + +skip_auth_type: ret = nl80211_set_conn_keys(params, msg); if (ret) goto nla_put_failure; @@ -8267,7 +8439,7 @@ static int wpa_driver_nl80211_associate( { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - int ret = -1; + int ret; struct nl_msg *msg; if (params->mode == IEEE80211_MODE_AP) @@ -8295,95 +8467,9 @@ static int wpa_driver_nl80211_associate( drv->ifindex); nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - if (params->bssid) { - wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, - MAC2STR(params->bssid)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); - } - if (params->freq) { - wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); - drv->assoc_freq = params->freq; - } else - drv->assoc_freq = 0; - if (params->bg_scan_period >= 0) { - wpa_printf(MSG_DEBUG, " * bg scan period=%d", - params->bg_scan_period); - NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD, - params->bg_scan_period); - } - if (params->ssid) { - wpa_hexdump_ascii(MSG_DEBUG, " * SSID", - params->ssid, params->ssid_len); - NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, - params->ssid); - if (params->ssid_len > sizeof(drv->ssid)) - goto nla_put_failure; - os_memcpy(drv->ssid, params->ssid, params->ssid_len); - drv->ssid_len = params->ssid_len; - } - wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); - if (params->wpa_ie) - NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, - params->wpa_ie); - - if (params->pairwise_suite != CIPHER_NONE) { - int cipher; - - switch (params->pairwise_suite) { - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } - wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); - } - - if (params->group_suite != CIPHER_NONE) { - int cipher; - - switch (params->group_suite) { - case CIPHER_WEP40: - cipher = WLAN_CIPHER_SUITE_WEP40; - break; - case CIPHER_WEP104: - cipher = WLAN_CIPHER_SUITE_WEP104; - break; - case CIPHER_CCMP: - cipher = WLAN_CIPHER_SUITE_CCMP; - break; - case CIPHER_GCMP: - cipher = WLAN_CIPHER_SUITE_GCMP; - break; - case CIPHER_TKIP: - default: - cipher = WLAN_CIPHER_SUITE_TKIP; - break; - } - wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); - NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); - } - -#ifdef CONFIG_IEEE80211W - if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) - NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); -#endif /* CONFIG_IEEE80211W */ - - NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); + ret = nl80211_connect_common(drv, params, msg); + if (ret) + goto nla_put_failure; if (params->prev_bssid) { wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, @@ -8392,33 +8478,6 @@ static int wpa_driver_nl80211_associate( params->prev_bssid); } - if (params->disable_ht) - NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT); - - if (params->htcaps && params->htcaps_mask) { - int sz = sizeof(struct ieee80211_ht_capabilities); - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps); - NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz, - params->htcaps_mask); - } - -#ifdef CONFIG_VHT_OVERRIDES - if (params->disable_vht) { - wpa_printf(MSG_DEBUG, " * VHT disabled"); - NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT); - } - - if (params->vhtcaps && params->vhtcaps_mask) { - int sz = sizeof(struct ieee80211_vht_capabilities); - NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps); - NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz, - params->vhtcaps_mask); - } -#endif /* CONFIG_VHT_OVERRIDES */ - - if (params->p2p) - wpa_printf(MSG_DEBUG, " * P2P group"); - ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { @@ -8593,8 +8652,9 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", - __func__, drv->operstate, state, state ? "UP" : "DORMANT"); + wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)", + bss->ifname, drv->operstate, state, + state ? "UP" : "DORMANT"); drv->operstate = state; return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1, state ? IF_OPER_UP : IF_OPER_DORMANT); @@ -8607,6 +8667,12 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; struct nl80211_sta_flag_update upd; + int ret = -ENOBUFS; + + if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) { + wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated"); + return 0; + } wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for " MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid)); @@ -8627,10 +8693,15 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); - return send_and_recv_msgs(drv, msg, NULL, NULL); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (!ret) + return 0; nla_put_failure: nlmsg_free(msg); - return -ENOBUFS; + wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)", + ret, strerror(-ret)); + return ret; } @@ -10209,6 +10280,18 @@ static int nl80211_set_param(void *priv, const char *param) } #endif /* CONFIG_P2P */ + if (os_strstr(param, "use_monitor=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + drv->use_monitor = 1; + } + + if (os_strstr(param, "force_connect_cmd=1")) { + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME; + } + return 0; } @@ -11321,7 +11404,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) settings->freq_params.center_freq1, settings->freq_params.center_freq2); - if (!drv->channel_switch_supported) { + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) { wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command"); return -EOPNOTSUPP; } @@ -11397,6 +11480,37 @@ error: } +static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set, + u8 qos_map_set_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map", + qos_map_set, qos_map_set_len); + + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) + wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed"); + + return ret; + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -11485,4 +11599,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #ifdef ANDROID .driver_cmd = wpa_driver_nl80211_driver_cmd, #endif /* ANDROID */ + .set_qos_map = nl80211_set_qos_map, }; diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 5742b988..7d306553 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -28,7 +28,6 @@ #include "common/ieee802_11_defs.h" #include "crypto/sha1.h" #include "l2_packet/l2_packet.h" -#include "p2p/p2p.h" #include "wps/wps.h" #include "driver.h" @@ -102,20 +101,6 @@ struct wpa_driver_test_data { unsigned int remain_on_channel_duration; int current_freq; - - struct p2p_data *p2p; - unsigned int off_channel_freq; - struct wpabuf *pending_action_tx; - u8 pending_action_src[ETH_ALEN]; - u8 pending_action_dst[ETH_ALEN]; - u8 pending_action_bssid[ETH_ALEN]; - unsigned int pending_action_freq; - unsigned int pending_action_no_cck; - unsigned int pending_listen_freq; - unsigned int pending_listen_duration; - int pending_p2p_scan; - struct sockaddr *probe_from; - socklen_t probe_from_len; }; @@ -125,7 +110,6 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, static void wpa_driver_test_close_test_socket( struct wpa_driver_test_data *drv); static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx); -static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv); static void test_driver_free_bss(struct test_driver_bss *bss) @@ -479,34 +463,6 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data, event.tx_status.ack = ret >= 0; wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); -#ifdef CONFIG_P2P - if (drv->p2p && - WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { - if (drv->pending_action_tx == NULL) { - wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " - "no pending operation"); - return ret; - } - - if (os_memcmp(hdr->addr1, drv->pending_action_dst, ETH_ALEN) != - 0) { - wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " - "unknown destination address"); - return ret; - } - - wpabuf_free(drv->pending_action_tx); - drv->pending_action_tx = NULL; - - p2p_send_action_cb(drv->p2p, drv->pending_action_freq, - drv->pending_action_dst, - drv->pending_action_src, - drv->pending_action_bssid, - ret >= 0); - } -#endif /* CONFIG_P2P */ - return ret; } @@ -553,10 +509,6 @@ static void test_driver_scan(struct wpa_driver_test_data *drv, event.rx_probe_req.ie = ie; event.rx_probe_req.ie_len = ielen; wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); -#ifdef CONFIG_P2P - if (drv->p2p) - p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); -#endif /* CONFIG_P2P */ } dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { @@ -1313,25 +1265,7 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) { - struct wpa_driver_test_data *drv = eloop_ctx; wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); - if (drv->pending_p2p_scan && drv->p2p) { -#ifdef CONFIG_P2P - size_t i; - struct os_time now; - os_get_time(&now); - for (i = 0; i < drv->num_scanres; i++) { - struct wpa_scan_res *bss = drv->scanres[i]; - if (p2p_scan_res_handler(drv->p2p, bss->bssid, - bss->freq, &now, bss->level, - (const u8 *) (bss + 1), - bss->ie_len) > 0) - return; - } - p2p_scan_res_handled(drv->p2p); -#endif /* CONFIG_P2P */ - return; - } wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } @@ -1949,30 +1883,8 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, data_len - (mgmt->u.probe_req.variable - data); wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); -#ifdef CONFIG_P2P - if (drv->p2p) - p2p_probe_req_rx(drv->p2p, mgmt->sa, - mgmt->da, mgmt->bssid, - event.rx_probe_req.ie, - event.rx_probe_req.ie_len); -#endif /* CONFIG_P2P */ } } - -#ifdef CONFIG_P2P - if (drv->p2p && - WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { - size_t hdr_len; - hdr_len = (const u8 *) - &mgmt->u.action.u.vs_public_action.action - data; - p2p_rx_action(drv->p2p, mgmt->da, mgmt->sa, mgmt->bssid, - mgmt->u.action.category, - &mgmt->u.action.u.vs_public_action.action, - data_len - hdr_len, freq); - } -#endif /* CONFIG_P2P */ - } @@ -1988,29 +1900,6 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, bss = dl_list_first(&drv->bss, struct test_driver_bss, list); /* data: optional [ STA-addr | ' ' | IEs(hex) ] */ -#ifdef CONFIG_P2P - if (drv->probe_req_report && drv->p2p && data_len) { - const char *d = (const char *) data; - u8 sa[ETH_ALEN]; - u8 ie[512]; - size_t ielen; - - if (hwaddr_aton(d, sa)) - return; - d += 18; - while (*d == ' ') - d++; - ielen = os_strlen(d) / 2; - if (ielen > sizeof(ie)) - ielen = sizeof(ie); - if (hexstr2bin(d, ie, ielen) < 0) - ielen = 0; - drv->probe_from = from; - drv->probe_from_len = fromlen; - p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen); - drv->probe_from = NULL; - } -#endif /* CONFIG_P2P */ if (!drv->ibss) return; @@ -2167,12 +2056,6 @@ static void wpa_driver_test_deinit(void *priv) struct test_client_socket *cli, *prev; int i; -#ifdef CONFIG_P2P - if (drv->p2p) - p2p_deinit(drv->p2p); - wpabuf_free(drv->pending_action_tx); -#endif /* CONFIG_P2P */ - cli = drv->cli; while (cli) { prev = cli; @@ -2369,13 +2252,6 @@ static int wpa_driver_test_set_param(void *priv, const char *param) drv->use_associnfo = 1; } - if (os_strstr(param, "p2p_mgmt=1")) { - wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P " - "management"); - if (wpa_driver_test_init_p2p(drv) < 0) - return -1; - } - return 0; } @@ -2465,8 +2341,6 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) { - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; os_memset(capa, 0, sizeof(*capa)); capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | @@ -2482,8 +2356,6 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; - if (drv->p2p) - capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT; capa->flags |= WPA_DRIVER_FLAGS_AP; capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE; @@ -2691,33 +2563,6 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, } -#ifdef CONFIG_P2P -static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_driver_test_data *drv = eloop_ctx; - - if (drv->pending_action_tx == NULL) - return; - - if (drv->off_channel_freq != drv->pending_action_freq) { - wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX " - "waiting for another freq=%u", - drv->pending_action_freq); - return; - } - wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to " - MACSTR, MAC2STR(drv->pending_action_dst)); - wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, - drv->pending_action_dst, - drv->pending_action_src, - drv->pending_action_bssid, - wpabuf_head(drv->pending_action_tx), - wpabuf_len(drv->pending_action_tx), - drv->pending_action_no_cck); -} -#endif /* CONFIG_P2P */ - - static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_test_data *drv = eloop_ctx; @@ -2729,9 +2574,6 @@ static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) data.remain_on_channel.freq = drv->remain_on_channel_freq; data.remain_on_channel.duration = drv->remain_on_channel_duration; - if (drv->p2p) - drv->off_channel_freq = 0; - drv->remain_on_channel_freq = 0; wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data); @@ -2765,18 +2607,6 @@ static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq, data.remain_on_channel.duration = duration; wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data); -#ifdef CONFIG_P2P - if (drv->p2p) { - drv->off_channel_freq = drv->remain_on_channel_freq; - test_send_action_cb(drv, NULL); - if (drv->off_channel_freq == drv->pending_listen_freq) { - p2p_listen_cb(drv->p2p, drv->pending_listen_freq, - drv->pending_listen_duration); - drv->pending_listen_freq = 0; - } - } -#endif /* CONFIG_P2P */ - return 0; } @@ -2804,470 +2634,6 @@ static int wpa_driver_test_probe_req_report(void *priv, int report) } -#ifdef CONFIG_P2P - -static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); - if (!drv->p2p) - return -1; - return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0); -} - - -static int wpa_driver_test_p2p_stop_find(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - if (!drv->p2p) - return -1; - p2p_stop_find(drv->p2p); - return 0; -} - - -static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); - if (!drv->p2p) - return -1; - return p2p_listen(drv->p2p, timeout); -} - - -static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr, - int wps_method, int go_intent, - const u8 *own_interface_addr, - unsigned int force_freq, - int persistent_group) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d " - "go_intent=%d " - "own_interface_addr=" MACSTR " force_freq=%u " - "persistent_group=%d)", - __func__, MAC2STR(peer_addr), wps_method, go_intent, - MAC2STR(own_interface_addr), force_freq, persistent_group); - if (!drv->p2p) - return -1; - return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent, - own_interface_addr, force_freq, persistent_group, - NULL, 0, 0, 0); -} - - -static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")", - __func__, MAC2STR(peer_addr)); - if (!drv->p2p) - return -1; - p2p_wps_success_cb(drv->p2p, peer_addr); - return 0; -} - - -static int wpa_driver_test_p2p_group_formation_failed(void *priv) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - if (!drv->p2p) - return -1; - p2p_group_formation_failed(drv->p2p); - return 0; -} - - -static int wpa_driver_test_p2p_set_params(void *priv, - const struct p2p_params *params) -{ - struct test_driver_bss *dbss = priv; - struct wpa_driver_test_data *drv = dbss->drv; - wpa_printf(MSG_DEBUG, "%s", __func__); - if (!drv->p2p) - return -1; - if (p2p_set_dev_name(drv->p2p, params->dev_name) < 0 || - p2p_set_pri_dev_type(drv->p2p, params->pri_dev_type) < 0 || - p2p_set_sec_dev_types(drv->p2p, params->sec_dev_type, - params->num_sec_dev_types) < 0) - return -1; - return 0; -} - - -static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, - unsigned int num_req_dev_types, - const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) -{ - struct wpa_driver_test_data *drv = ctx; - struct wpa_driver_scan_params params; - int ret; - struct wpabuf *wps_ie, *ies; - int social_channels[] = { 2412, 2437, 2462, 0, 0 }; - size_t ielen; - - wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)", - __func__, type, freq); - - os_memset(¶ms, 0, sizeof(params)); - - /* P2P Wildcard SSID */ - params.num_ssids = 1; - params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; - params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; - -#if 0 /* TODO: WPS IE */ - wpa_s->wps->dev.p2p = 1; - wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, - wpa_s->wps->uuid, WPS_REQ_ENROLLEE); -#else - wps_ie = wpabuf_alloc(1); -#endif - if (wps_ie == NULL) - return -1; - - ielen = p2p_scan_ie_buf_len(drv->p2p); - ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); - if (ies == NULL) { - wpabuf_free(wps_ie); - return -1; - } - wpabuf_put_buf(ies, wps_ie); - wpabuf_free(wps_ie); - - p2p_scan_ie(drv->p2p, ies, dev_id); - - params.extra_ies = wpabuf_head(ies); - params.extra_ies_len = wpabuf_len(ies); - - switch (type) { - case P2P_SCAN_SOCIAL: - params.freqs = social_channels; - break; - case P2P_SCAN_FULL: - break; - case P2P_SCAN_SOCIAL_PLUS_ONE: - social_channels[3] = freq; - params.freqs = social_channels; - break; - } - - drv->pending_p2p_scan = 1; - ret = wpa_driver_test_scan(drv, ¶ms); - - wpabuf_free(ies); - - return ret; -} - - -static int test_send_action(void *ctx, unsigned int freq, const u8 *dst, - const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time) -{ - struct wpa_driver_test_data *drv = ctx; - - wpa_printf(MSG_DEBUG, "%s(freq=%u dst=" MACSTR " src=" MACSTR - " bssid=" MACSTR " len=%d", - __func__, freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), - (int) len); - if (freq <= 0) { - wpa_printf(MSG_WARNING, "P2P: No frequency specified for " - "action frame TX"); - return -1; - } - - if (drv->pending_action_tx) { - wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX " - "to " MACSTR, MAC2STR(drv->pending_action_dst)); - wpabuf_free(drv->pending_action_tx); - } - drv->pending_action_tx = wpabuf_alloc(len); - if (drv->pending_action_tx == NULL) - return -1; - wpabuf_put_data(drv->pending_action_tx, buf, len); - os_memcpy(drv->pending_action_src, src, ETH_ALEN); - os_memcpy(drv->pending_action_dst, dst, ETH_ALEN); - os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN); - drv->pending_action_freq = freq; - drv->pending_action_no_cck = 1; - - if (drv->off_channel_freq == freq) { - /* Already on requested channel; send immediately */ - /* TODO: Would there ever be need to extend the current - * duration on the channel? */ - eloop_cancel_timeout(test_send_action_cb, drv, NULL); - eloop_register_timeout(0, 0, test_send_action_cb, drv, NULL); - return 0; - } - - wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted " - "once the driver gets to the requested channel"); - if (wpa_driver_test_remain_on_channel(drv, freq, wait_time) < 0) { - wpa_printf(MSG_DEBUG, "P2P: Failed to request driver " - "to remain on channel (%u MHz) for Action " - "Frame TX", freq); - return -1; - } - - return 0; -} - - -static void test_send_action_done(void *ctx) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static void test_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) -{ - struct wpa_driver_test_data *drv = ctx; - union wpa_event_data event; - wpa_printf(MSG_DEBUG, "%s", __func__); - os_memset(&event, 0, sizeof(event)); - event.p2p_go_neg_completed.res = res; - wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_COMPLETED, &event); -} - - -static void test_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) -{ - struct wpa_driver_test_data *drv = ctx; - union wpa_event_data event; - wpa_printf(MSG_DEBUG, "%s(src=" MACSTR ")", __func__, MAC2STR(src)); - os_memset(&event, 0, sizeof(event)); - event.p2p_go_neg_req_rx.src = src; - event.p2p_go_neg_req_rx.dev_passwd_id = dev_passwd_id; - wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_REQ_RX, &event); -} - - -static void test_dev_found(void *ctx, const u8 *addr, - const struct p2p_peer_info *info, int new_device) -{ - struct wpa_driver_test_data *drv = ctx; - union wpa_event_data event; - char devtype[WPS_DEV_TYPE_BUFSIZE]; - wpa_printf(MSG_DEBUG, "%s(" MACSTR " p2p_dev_addr=" MACSTR - " pri_dev_type=%s name='%s' config_methods=0x%x " - "dev_capab=0x%x group_capab=0x%x)", - __func__, MAC2STR(addr), MAC2STR(info->p2p_device_addr), - wps_dev_type_bin2str(info->pri_dev_type, devtype, - sizeof(devtype)), - info->device_name, info->config_methods, info->dev_capab, - info->group_capab); - - os_memset(&event, 0, sizeof(event)); - event.p2p_dev_found.addr = addr; - event.p2p_dev_found.dev_addr = info->p2p_device_addr; - event.p2p_dev_found.pri_dev_type = info->pri_dev_type; - event.p2p_dev_found.dev_name = info->device_name; - event.p2p_dev_found.config_methods = info->config_methods; - event.p2p_dev_found.dev_capab = info->dev_capab; - event.p2p_dev_found.group_capab = info->group_capab; - wpa_supplicant_event(drv->ctx, EVENT_P2P_DEV_FOUND, &event); -} - - -static int test_start_listen(void *ctx, unsigned int freq, - unsigned int duration, - const struct wpabuf *probe_resp_ie) -{ - struct wpa_driver_test_data *drv = ctx; - - wpa_printf(MSG_DEBUG, "%s(freq=%u duration=%u)", - __func__, freq, duration); - - if (wpa_driver_test_probe_req_report(drv, 1) < 0) - return -1; - - drv->pending_listen_freq = freq; - drv->pending_listen_duration = duration; - - if (wpa_driver_test_remain_on_channel(drv, freq, duration) < 0) { - drv->pending_listen_freq = 0; - return -1; - } - - return 0; -} - - -static void test_stop_listen(void *ctx) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static int test_send_probe_resp(void *ctx, const struct wpabuf *buf) -{ - struct wpa_driver_test_data *drv = ctx; - char resp[512], *pos, *end; - int ret; - const struct ieee80211_mgmt *mgmt; - const u8 *ie, *ie_end; - - wpa_printf(MSG_DEBUG, "%s", __func__); - wpa_hexdump_buf(MSG_MSGDUMP, "Probe Response", buf); - if (wpabuf_len(buf) < 24) - return -1; - if (!drv->probe_from) { - wpa_printf(MSG_DEBUG, "%s: probe_from not set", __func__); - return -1; - } - - pos = resp; - end = resp + sizeof(resp); - - mgmt = wpabuf_head(buf); - - /* reply: SCANRESP BSSID SSID IEs */ - ret = os_snprintf(pos, end - pos, "SCANRESP " MACSTR " ", - MAC2STR(mgmt->bssid)); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - - ie = mgmt->u.probe_resp.variable; - ie_end = wpabuf_head_u8(buf) + wpabuf_len(buf); - if (ie_end - ie < 2 || ie[0] != WLAN_EID_SSID || - ie + 2 + ie[1] > ie_end) - return -1; - pos += wpa_snprintf_hex(pos, end - pos, ie + 2, ie[1]); - - ret = os_snprintf(pos, end - pos, " "); - if (ret < 0 || ret >= end - pos) - return -1; - pos += ret; - pos += wpa_snprintf_hex(pos, end - pos, ie, ie_end - ie); - - sendto(drv->test_socket, resp, pos - resp, 0, - drv->probe_from, drv->probe_from_len); - - return 0; -} - - -static void test_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, - u16 update_indic, const u8 *tlvs, size_t tlvs_len) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic, - const u8 *tlvs, size_t tlvs_len) -{ - wpa_printf(MSG_DEBUG, "%s", __func__); - /* TODO */ -} - - -static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, - const u8 *dev_addr, const u8 *pri_dev_type, - const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab, - const u8 *group_id, size_t group_id_len) -{ - wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", - __func__, MAC2STR(peer), config_methods); - /* TODO */ -} - - -static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) -{ - wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", - __func__, MAC2STR(peer), config_methods); - /* TODO */ -} - - -static void test_p2p_debug_print(void *ctx, int level, const char *msg) -{ - wpa_printf(level, "P2P: %s", msg); -} - -#endif /* CONFIG_P2P */ - - -static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv) -{ -#ifdef CONFIG_P2P - struct p2p_config p2p; - unsigned int r; - int i; - - os_memset(&p2p, 0, sizeof(p2p)); - p2p.cb_ctx = drv; - p2p.debug_print = test_p2p_debug_print; - p2p.p2p_scan = test_p2p_scan; - p2p.send_action = test_send_action; - p2p.send_action_done = test_send_action_done; - p2p.go_neg_completed = test_go_neg_completed; - p2p.go_neg_req_rx = test_go_neg_req_rx; - p2p.dev_found = test_dev_found; - p2p.start_listen = test_start_listen; - p2p.stop_listen = test_stop_listen; - p2p.send_probe_resp = test_send_probe_resp; - p2p.sd_request = test_sd_request; - p2p.sd_response = test_sd_response; - p2p.prov_disc_req = test_prov_disc_req; - p2p.prov_disc_resp = test_prov_disc_resp; - - os_memcpy(p2p.dev_addr, drv->own_addr, ETH_ALEN); - - p2p.reg_class = 12; /* TODO: change depending on location */ - /* - * Pick one of the social channels randomly as the listen - * channel. - */ - os_get_random((u8 *) &r, sizeof(r)); - p2p.channel = 1 + (r % 3) * 5; - - /* TODO: change depending on location */ - p2p.op_reg_class = 12; - /* - * For initial tests, pick the operation channel randomly. - * TODO: Use scan results (etc.) to select the best channel. - */ - p2p.op_channel = 1 + r % 11; - - os_memcpy(p2p.country, "US ", 3); - - /* FIX: fetch available channels from the driver */ - p2p.channels.reg_classes = 1; - p2p.channels.reg_class[0].reg_class = 12; /* US/12 = 2.4 GHz band */ - p2p.channels.reg_class[0].channels = 11; - for (i = 0; i < 11; i++) - p2p.channels.reg_class[0].channel[i] = i + 1; - - p2p.max_peers = 100; - - drv->p2p = p2p_init(&p2p); - if (drv->p2p == NULL) - return -1; - return 0; -#else /* CONFIG_P2P */ - wpa_printf(MSG_INFO, "driver_test: P2P support not included"); - return -1; -#endif /* CONFIG_P2P */ -} - - const struct wpa_driver_ops wpa_driver_test_ops = { "test", "wpa_supplicant test driver", @@ -3309,14 +2675,4 @@ const struct wpa_driver_ops wpa_driver_test_ops = { .remain_on_channel = wpa_driver_test_remain_on_channel, .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel, .probe_req_report = wpa_driver_test_probe_req_report, -#ifdef CONFIG_P2P - .p2p_find = wpa_driver_test_p2p_find, - .p2p_stop_find = wpa_driver_test_p2p_stop_find, - .p2p_listen = wpa_driver_test_p2p_listen, - .p2p_connect = wpa_driver_test_p2p_connect, - .wps_success_cb = wpa_driver_test_wps_success_cb, - .p2p_group_formation_failed = - wpa_driver_test_p2p_group_formation_failed, - .p2p_set_params = wpa_driver_test_p2p_set_params, -#endif /* CONFIG_P2P */ }; diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 6e2e771b..e5734bdd 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -31,10 +31,6 @@ #include "driver.h" #include "driver_wext.h" -#ifdef ANDROID -#include "android_drv.h" -#endif /* ANDROID */ - static int wpa_driver_wext_flush_pmkid(void *priv); static int wpa_driver_wext_get_range(void *priv); static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); @@ -299,14 +295,6 @@ wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) } wpa_supplicant_event(ctx, EVENT_STKSTART, &data); #endif /* CONFIG_PEERKEY */ -#ifdef ANDROID - } else if (os_strncmp(custom, "STOP", 4) == 0) { - wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); - } else if (os_strncmp(custom, "START", 5) == 0) { - wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); - } else if (os_strncmp(custom, "HANG", 4) == 0) { - wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); -#endif /* ANDROID */ } } @@ -858,12 +846,6 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname) drv->mlme_sock = -1; -#ifdef ANDROID - drv->errors = 0; - drv->driver_is_started = TRUE; - drv->bgscan_enabled = 0; -#endif /* ANDROID */ - if (wpa_driver_wext_finish_drv_init(drv) < 0) goto err3; @@ -1869,10 +1851,8 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) { struct iwreq iwr; const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; -#ifndef ANDROID u8 ssid[32]; int i; -#endif /* ANDROID */ /* * Only force-disconnect when the card is in infrastructure mode, @@ -1893,7 +1873,6 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) "selection on disconnect"); } -#ifndef ANDROID if (drv->cfg80211) { /* * cfg80211 supports SIOCSIWMLME commands, so there is @@ -1919,7 +1898,6 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " "SSID to disconnect"); } -#endif /* ANDROID */ } } @@ -1960,15 +1938,15 @@ static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie, int wpa_driver_wext_cipher2wext(int cipher) { switch (cipher) { - case CIPHER_NONE: + case WPA_CIPHER_NONE: return IW_AUTH_CIPHER_NONE; - case CIPHER_WEP40: + case WPA_CIPHER_WEP40: return IW_AUTH_CIPHER_WEP40; - case CIPHER_TKIP: + case WPA_CIPHER_TKIP: return IW_AUTH_CIPHER_TKIP; - case CIPHER_CCMP: + case WPA_CIPHER_CCMP: return IW_AUTH_CIPHER_CCMP; - case CIPHER_WEP104: + case WPA_CIPHER_WEP104: return IW_AUTH_CIPHER_WEP104; default: return 0; @@ -1979,10 +1957,10 @@ int wpa_driver_wext_cipher2wext(int cipher) int wpa_driver_wext_keymgmt2wext(int keymgmt) { switch (keymgmt) { - case KEY_MGMT_802_1X: - case KEY_MGMT_802_1X_NO_WPA: + case WPA_KEY_MGMT_IEEE8021X: + case WPA_KEY_MGMT_IEEE8021X_NO_WPA: return IW_AUTH_KEY_MGMT_802_1X; - case KEY_MGMT_PSK: + case WPA_KEY_MGMT_PSK: return IW_AUTH_KEY_MGMT_PSK; default: return 0; @@ -2099,9 +2077,9 @@ int wpa_driver_wext_associate(void *priv, if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0) ret = -1; - value = params->key_mgmt_suite != KEY_MGMT_NONE || - params->pairwise_suite != CIPHER_NONE || - params->group_suite != CIPHER_NONE || + value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE || + params->pairwise_suite != WPA_CIPHER_NONE || + params->group_suite != WPA_CIPHER_NONE || params->wpa_ie_len; if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_PRIVACY_INVOKED, value) < 0) @@ -2110,8 +2088,8 @@ int wpa_driver_wext_associate(void *priv, /* Allow unencrypted EAPOL messages even if pairwise keys are set when * not using WPA. IEEE 802.1X specifies that these frames are not * encrypted, but WPA encrypts them when pairwise keys are in use. */ - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK) + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK) allow_unencrypted_eapol = 0; else allow_unencrypted_eapol = 1; @@ -2338,129 +2316,6 @@ static const char * wext_get_radio_name(void *priv) } -#ifdef ANDROID - -static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd) -{ - struct iwreq iwr; - char buf[MAX_DRV_CMD_SIZE]; - int ret; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - os_memset(buf, 0, sizeof(buf)); - os_strlcpy(buf, cmd, sizeof(buf)); - - iwr.u.data.pointer = buf; - iwr.u.data.length = sizeof(buf); - - ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); - - if (ret < 0) { - wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, - cmd); - drv->errors++; - if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { - drv->errors = 0; - wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE - "HANGED"); - } - return ret; - } - - drv->errors = 0; - return 0; -} - - -static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params, - u32 interval) -{ - struct wpa_driver_wext_data *drv = priv; - struct iwreq iwr; - int ret = 0, i = 0, bp; - char buf[WEXT_PNO_MAX_COMMAND_SIZE]; - - bp = WEXT_PNOSETUP_HEADER_SIZE; - os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp); - buf[bp++] = WEXT_PNO_TLV_PREFIX; - buf[bp++] = WEXT_PNO_TLV_VERSION; - buf[bp++] = WEXT_PNO_TLV_SUBVERSION; - buf[bp++] = WEXT_PNO_TLV_RESERVED; - - while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) { - /* - * Check that there is enough space needed for 1 more SSID, the - * other sections and null termination. - */ - if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE + - WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf)) - break; - - wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan", - params->ssids[i].ssid, - params->ssids[i].ssid_len); - buf[bp++] = WEXT_PNO_SSID_SECTION; - buf[bp++] = params->ssids[i].ssid_len; - os_memcpy(&buf[bp], params->ssids[i].ssid, - params->ssids[i].ssid_len); - bp += params->ssids[i].ssid_len; - i++; - } - - buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION; - /* TODO: consider using interval parameter (interval in msec) instead - * of hardcoded value here */ - os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", - WEXT_PNO_SCAN_INTERVAL); - bp += WEXT_PNO_SCAN_INTERVAL_LENGTH; - - buf[bp++] = WEXT_PNO_REPEAT_SECTION; - os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", - WEXT_PNO_REPEAT); - bp += WEXT_PNO_REPEAT_LENGTH; - - buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION; - os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", - WEXT_PNO_MAX_REPEAT); - bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = buf; - iwr.u.data.length = bp; - - ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr); - if (ret < 0) { - wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", - ret); - drv->errors++; - if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { - drv->errors = 0; - wpa_msg(drv->ctx, MSG_INFO, - WPA_EVENT_DRIVER_STATE "HANGED"); - } - return ret; - } - - drv->errors = 0; - drv->bgscan_enabled = 1; - - return android_wext_cmd(drv, "PNOFORCE 1"); -} - - -static int wext_stop_sched_scan(void *priv) -{ - struct wpa_driver_wext_data *drv = priv; - drv->bgscan_enabled = 0; - return android_wext_cmd(drv, "PNOFORCE 0"); -} - -#endif /* ANDROID */ - - const struct wpa_driver_ops wpa_driver_wext_ops = { .name = "wext", .desc = "Linux wireless extensions (generic)", @@ -2480,8 +2335,4 @@ const struct wpa_driver_ops wpa_driver_wext_ops = { .get_capa = wpa_driver_wext_get_capa, .set_operstate = wpa_driver_wext_set_operstate, .get_radio_name = wext_get_radio_name, -#ifdef ANDROID - .sched_scan = wext_sched_scan, - .stop_sched_scan = wext_stop_sched_scan, -#endif /* ANDROID */ }; diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index c4a5bc99..b4b5960a 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -44,12 +44,6 @@ struct wpa_driver_wext_data { int cfg80211; /* whether driver is using cfg80211 */ u8 max_level; - -#ifdef ANDROID - int errors; - int driver_is_started; - int bgscan_enabled; -#endif /* ANDROID */ }; int wpa_driver_wext_get_bssid(void *priv, u8 *bssid); diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index 04eb4fd1..446ab639 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -6,8 +6,9 @@ * See README for more details. */ -#include "includes.h" - +#include "utils/includes.h" +#include "utils/common.h" +#include "driver.h" #ifdef CONFIG_DRIVER_WEXT extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c index 6c60550f..2fa20b1e 100644 --- a/src/drivers/netlink.c +++ b/src/drivers/netlink.c @@ -1,6 +1,6 @@ /* * Netlink helper functions for driver wrappers - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -137,6 +137,35 @@ void netlink_deinit(struct netlink_data *netlink) os_free(netlink); } + +static const char * linkmode_str(int mode) +{ + switch (mode) { + case -1: + return "no change"; + case 0: + return "kernel-control"; + case 1: + return "userspace-control"; + } + return "?"; +} + + +static const char * operstate_str(int state) +{ + switch (state) { + case -1: + return "no change"; + case IF_OPER_DORMANT: + return "IF_OPER_DORMANT"; + case IF_OPER_UP: + return "IF_OPER_UP"; + } + return "?"; +} + + int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, int linkmode, int operstate) { @@ -184,8 +213,9 @@ int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, RTA_LENGTH(sizeof(char)); } - wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d", - linkmode, operstate); + wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)", + ifindex, linkmode, linkmode_str(linkmode), + operstate, operstate_str(operstate)); ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0); if (ret < 0) { diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index f752e982..91054fd6 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -581,7 +581,14 @@ * operation, %NL80211_ATTR_MAC contains the peer MAC address, and * %NL80211_ATTR_REASON_CODE the reason code to be used (only with * %NL80211_TDLS_TEARDOWN). - * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The + * %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be + * sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as + * 802.11 management frames, while TDLS action codes (802.11-2012 + * 8.5.13.1) will be encapsulated and sent as data frames. The currently + * supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES + * and the currently supported TDLS actions codes are given in + * &enum ieee80211_tdls_actioncode. * * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP * (or GO) interface (i.e. hostapd) to ask for unexpected frames to @@ -686,6 +693,21 @@ * other station that transmission must be blocked until the channel * switch is complete. * + * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified + * by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in + * %NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in + * %NL80211_ATTR_VENDOR_DATA. + * For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is + * used in the wiphy data as a nested attribute containing descriptions + * (&struct nl80211_vendor_cmd_info) of the supported vendor commands. + * This may also be sent as an event with the same attributes. + * + * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values. + * The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If + * that attribute is not included, QoS mapping is disabled. Since this + * QoS mapping is relevant for IP packets, it is only valid during an + * association. This is cleared on disassociation and AP restart. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -853,6 +875,10 @@ enum nl80211_commands { NL80211_CMD_CHANNEL_SWITCH, + NL80211_CMD_VENDOR, + + NL80211_CMD_SET_QOS_MAP, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1508,6 +1534,27 @@ enum nl80211_commands { * to react to radar events, e.g. initiate a channel switch or leave the * IBSS network. * + * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports + * 5 MHz channel bandwidth. + * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports + * 10 MHz channel bandwidth. + * + * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode + * Notification Element based on association request when used with + * %NL80211_CMD_NEW_STATION; u8 attribute. + * + * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if + * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet) + * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command + * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this + * attribute is also used for vendor command feature advertisement + * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy + * info, containing a nested array of possible events + * + * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This + * data is in the format defined for the payload of the QoS Map Set element + * in IEEE Std 802.11-2012, 8.4.2.97. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1824,6 +1871,18 @@ enum nl80211_attrs { NL80211_ATTR_HANDLE_DFS, + NL80211_ATTR_SUPPORT_5_MHZ, + NL80211_ATTR_SUPPORT_10_MHZ, + + NL80211_ATTR_OPMODE_NOTIF, + + NL80211_ATTR_VENDOR_ID, + NL80211_ATTR_VENDOR_SUBCMD, + NL80211_ATTR_VENDOR_DATA, + NL80211_ATTR_VENDOR_EVENTS, + + NL80211_ATTR_QOS_MAP, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2224,10 +2283,9 @@ enum nl80211_band_attr { * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current * regulatory domain. - * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is - * permitted on this channel in current regulatory domain. - * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted - * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation + * are permitted on this channel, this includes sending probe + * requests, or modes of operation that require beaconing. * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm @@ -2254,8 +2312,8 @@ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, NL80211_FREQUENCY_ATTR_FREQ, NL80211_FREQUENCY_ATTR_DISABLED, - NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, - NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_NO_IR, + __NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_RADAR, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, NL80211_FREQUENCY_ATTR_DFS_STATE, @@ -2271,6 +2329,9 @@ enum nl80211_frequency_attr { }; #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER +#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR /** * enum nl80211_bitrate_attr - bitrate attributes @@ -2413,8 +2474,9 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_DFS: DFS support is required to be used * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links - * @NL80211_RRF_PASSIVE_SCAN: passive scan is required - * @NL80211_RRF_NO_IBSS: no IBSS is allowed + * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, + * this includes probe requests or modes of operation that require + * beaconing. */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -2424,10 +2486,17 @@ enum nl80211_reg_rule_flags { NL80211_RRF_DFS = 1<<4, NL80211_RRF_PTP_ONLY = 1<<5, NL80211_RRF_PTMP_ONLY = 1<<6, - NL80211_RRF_PASSIVE_SCAN = 1<<7, - NL80211_RRF_NO_IBSS = 1<<8, + NL80211_RRF_NO_IR = 1<<7, + __NL80211_RRF_NO_IBSS = 1<<8, }; +#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR + +/* For backport compatibility with older userspace */ +#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) + /** * enum nl80211_dfs_regions - regulatory DFS regions * @@ -3058,21 +3127,35 @@ enum nl80211_key_attributes { * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with * 1 = 500 kbps) but without the IE length restriction (at most * %NL80211_MAX_SUPP_RATES in a single array). - * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection * in an array of MCS numbers. + * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, + * see &struct nl80211_txrate_vht * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ enum nl80211_tx_rate_attributes { __NL80211_TXRATE_INVALID, NL80211_TXRATE_LEGACY, - NL80211_TXRATE_MCS, + NL80211_TXRATE_HT, + NL80211_TXRATE_VHT, /* keep last */ __NL80211_TXRATE_AFTER_LAST, NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 }; +#define NL80211_TXRATE_MCS NL80211_TXRATE_HT +#define NL80211_VHT_NSS_MAX 8 + +/** + * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap + * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) + */ +struct nl80211_txrate_vht { + __u16 mcs[NL80211_VHT_NSS_MAX]; +}; + /** * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band @@ -3934,4 +4017,24 @@ enum nl80211_rxmgmt_flags { NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, }; +/* + * If this flag is unset, the lower 24 bits are an OUI, if set + * a Linux nl80211 vendor ID is used (no such IDs are allocated + * yet, so that's not valid so far) + */ +#define NL80211_VENDOR_ID_IS_LINUX 0x80000000 + +/** + * struct nl80211_vendor_cmd_info - vendor command data + * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the + * value is a 24-bit OUI; if it is set then a separately allocated ID + * may be used, but no such IDs are allocated yet. New IDs should be + * added to this file when needed. + * @subcmd: sub-command ID for the command + */ +struct nl80211_vendor_cmd_info { + __u32 vendor_id; + __u32 subcmd; +}; + #endif /* __LINUX_NL80211_H */ diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h index 74d6ce58..62320880 100644 --- a/src/drivers/priv_netlink.h +++ b/src/drivers/priv_netlink.h @@ -69,6 +69,7 @@ (struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len))) #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) #define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0))) +#define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0)) struct sockaddr_nl diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 3439c2df..98abd4ef 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -1,6 +1,6 @@ /* * EAP peer state machines (RFC 4137) - * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -388,10 +388,11 @@ SM_STATE(EAP, METHOD) sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret, eapReqData); wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s " - "methodState=%s decision=%s", + "methodState=%s decision=%s eapRespData=%p", ret.ignore ? "TRUE" : "FALSE", eap_sm_method_state_txt(ret.methodState), - eap_sm_decision_txt(ret.decision)); + eap_sm_decision_txt(ret.decision), + sm->eapRespData); sm->ignore = ret.ignore; if (sm->ignore) @@ -432,8 +433,10 @@ SM_STATE(EAP, SEND_RESPONSE) sm->lastId = sm->reqId; sm->lastRespData = wpabuf_dup(sm->eapRespData); eapol_set_bool(sm, EAPOL_eapResp, TRUE); - } else + } else { + wpa_printf(MSG_DEBUG, "EAP: No eapRespData available"); sm->lastRespData = NULL; + } eapol_set_bool(sm, EAPOL_eapReq, FALSE); eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); } @@ -724,8 +727,19 @@ static void eap_peer_sm_step_local(struct eap_sm *sm) SM_ENTER(EAP, SEND_RESPONSE); break; case EAP_METHOD: + /* + * Note: RFC 4137 uses methodState == DONE && decision == FAIL + * as the condition. eapRespData == NULL here is used to allow + * final EAP method response to be sent without having to change + * all methods to either use methodState MAY_CONT or leaving + * decision to something else than FAIL in cases where the only + * expected response is EAP-Failure. + */ if (sm->ignore) SM_ENTER(EAP, DISCARD); + else if (sm->methodState == METHOD_DONE && + sm->decision == DECISION_FAIL && !sm->eapRespData) + SM_ENTER(EAP, FAILURE); else SM_ENTER(EAP, SEND_RESPONSE); break; diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c index c71db5fd..864ea1d9 100644 --- a/src/eap_peer/eap_eke.c +++ b/src/eap_peer/eap_eke.c @@ -28,6 +28,10 @@ struct eap_eke_data { u8 nonce_p[EAP_EKE_MAX_NONCE_LEN]; u8 nonce_s[EAP_EKE_MAX_NONCE_LEN]; struct wpabuf *msgs; + u8 dhgroup; /* forced DH group or 0 to allow all supported */ + u8 encr; /* forced encryption algorithm or 0 to allow all supported */ + u8 prf; /* forced PRF or 0 to allow all supported */ + u8 mac; /* forced MAC or 0 to allow all supported */ }; @@ -66,6 +70,7 @@ static void * eap_eke_init(struct eap_sm *sm) struct eap_eke_data *data; const u8 *identity, *password; size_t identity_len, password_len; + const char *phase1; password = eap_get_config_password(sm, &password_len); if (!password) { @@ -89,6 +94,39 @@ static void * eap_eke_init(struct eap_sm *sm) data->peerid_len = identity_len; } + phase1 = eap_get_config_phase1(sm); + if (phase1) { + const char *pos; + + pos = os_strstr(phase1, "dhgroup="); + if (pos) { + data->dhgroup = atoi(pos + 8); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u", + data->dhgroup); + } + + pos = os_strstr(phase1, "encr="); + if (pos) { + data->encr = atoi(pos + 5); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u", + data->encr); + } + + pos = os_strstr(phase1, "prf="); + if (pos) { + data->prf = atoi(pos + 4); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u", + data->prf); + } + + pos = os_strstr(phase1, "mac="); + if (pos) { + data->mac = atoi(pos + 4); + wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u", + data->mac); + } + } + return data; } @@ -226,16 +264,20 @@ static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data, i, pos[0], pos[1], pos[2], pos[3]); pos += 4; - if (!eap_eke_supp_dhgroup(*tmp)) + if ((data->dhgroup && data->dhgroup != *tmp) || + !eap_eke_supp_dhgroup(*tmp)) continue; tmp++; - if (!eap_eke_supp_encr(*tmp)) + if ((data->encr && data->encr != *tmp) || + !eap_eke_supp_encr(*tmp)) continue; tmp++; - if (!eap_eke_supp_prf(*tmp)) + if ((data->prf && data->prf != *tmp) || + !eap_eke_supp_prf(*tmp)) continue; tmp++; - if (!eap_eke_supp_mac(*tmp)) + if ((data->mac && data->mac != *tmp) || + !eap_eke_supp_mac(*tmp)) continue; prop = tmp - 3; diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c index 8a0644d0..5b023c79 100644 --- a/src/eap_peer/eap_gpsk.c +++ b/src/eap_peer/eap_gpsk.c @@ -1,6 +1,6 @@ /* * EAP peer method: EAP-GPSK (RFC 5433) - * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -33,6 +33,7 @@ struct eap_gpsk_data { int specifier; /* CSuite/Specifier */ u8 *psk; size_t psk_len; + u16 forced_cipher; /* force cipher or 0 to allow all supported */ }; @@ -80,6 +81,7 @@ static void * eap_gpsk_init(struct eap_sm *sm) struct eap_gpsk_data *data; const u8 *identity, *password; size_t identity_len, password_len; + const char *phase1; password = eap_get_config_password(sm, &password_len); if (password == NULL) { @@ -103,6 +105,18 @@ static void * eap_gpsk_init(struct eap_sm *sm) data->id_peer_len = identity_len; } + phase1 = eap_get_config_phase1(sm); + if (phase1) { + const char *pos; + + pos = os_strstr(phase1, "cipher="); + if (pos) { + data->forced_cipher = atoi(pos + 7); + wpa_printf(MSG_DEBUG, "EAP-GPSK: Forced cipher %u", + data->forced_cipher); + } + } + data->psk = os_malloc(password_len); if (data->psk == NULL) { eap_gpsk_deinit(sm, data); @@ -195,7 +209,9 @@ static int eap_gpsk_select_csuite(struct eap_sm *sm, i, vendor, specifier); if (data->vendor == EAP_GPSK_VENDOR_IETF && data->specifier == EAP_GPSK_CIPHER_RESERVED && - eap_gpsk_supported_ciphersuite(vendor, specifier)) { + eap_gpsk_supported_ciphersuite(vendor, specifier) && + (!data->forced_cipher || data->forced_cipher == specifier)) + { data->vendor = vendor; data->specifier = specifier; } @@ -273,6 +289,7 @@ static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm, pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list, &csuite_list_len, pos, end); if (pos == NULL) { + ret->methodState = METHOD_DONE; eap_gpsk_state(data, FAILURE); return NULL; } diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c index 09a655ec..2d7841dd 100644 --- a/src/eap_peer/eap_ikev2.c +++ b/src/eap_peer/eap_ikev2.c @@ -1,6 +1,6 @@ /* * EAP-IKEv2 peer (RFC 5106) - * Copyright (c) 2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2007-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -60,6 +60,7 @@ static void * eap_ikev2_init(struct eap_sm *sm) struct eap_ikev2_data *data; const u8 *identity, *password; size_t identity_len, password_len; + int fragment_size; identity = eap_get_config_identity(sm, &identity_len); if (identity == NULL) { @@ -71,7 +72,11 @@ static void * eap_ikev2_init(struct eap_sm *sm) if (data == NULL) return NULL; data->state = WAIT_START; - data->fragment_size = IKEV2_FRAGMENT_SIZE; + fragment_size = eap_get_config_fragment_size(sm); + if (fragment_size <= 0) + data->fragment_size = IKEV2_FRAGMENT_SIZE; + else + data->fragment_size = fragment_size; data->ikev2.state = SA_INIT; data->ikev2.peer_auth = PEER_AUTH_SECRET; data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 3b932090..8634f754 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -22,7 +22,6 @@ /* Maximum supported PEAP version * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt - * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt */ #define EAP_PEAP_VERSION 1 @@ -315,8 +314,6 @@ static int eap_tlv_add_cryptobinding(struct eap_sm *sm, len[1] = 1; tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; - if (data->peap_version >= 2) - tlv_type |= EAP_TLV_TYPE_MANDATORY; wpabuf_put_be16(buf, tlv_type); wpabuf_put_be16(buf, 56); @@ -580,33 +577,6 @@ static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, } -static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) -{ - struct wpabuf *e; - struct eap_tlv_hdr *tlv; - - if (buf == NULL) - return NULL; - - /* Encapsulate EAP packet in EAP-Payload TLV */ - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); - e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); - if (e == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " - "for TLV encapsulation"); - wpabuf_free(buf); - return NULL; - } - tlv = wpabuf_put(e, sizeof(*tlv)); - tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_EAP_PAYLOAD_TLV); - tlv->length = host_to_be16(wpabuf_len(buf)); - wpabuf_put_buf(e, buf); - wpabuf_free(buf); - return e; -} - - static int eap_peap_phase2_request(struct eap_sm *sm, struct eap_peap_data *data, struct eap_method_ret *ret, @@ -837,49 +807,6 @@ continue_req: in_decrypted = nmsg; } - if (data->peap_version >= 2) { - struct eap_tlv_hdr *tlv; - struct wpabuf *nmsg; - - if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " - "EAP TLV"); - wpabuf_free(in_decrypted); - return 0; - } - tlv = wpabuf_mhead(in_decrypted); - if ((be_to_host16(tlv->tlv_type) & 0x3fff) != - EAP_TLV_EAP_PAYLOAD_TLV) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); - wpabuf_free(in_decrypted); - return 0; - } - if (sizeof(*tlv) + be_to_host16(tlv->length) > - wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " - "length"); - wpabuf_free(in_decrypted); - return 0; - } - hdr = (struct eap_hdr *) (tlv + 1); - if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " - "EAP packet in EAP TLV"); - wpabuf_free(in_decrypted); - return 0; - } - - nmsg = wpabuf_alloc(be_to_host16(hdr->length)); - if (nmsg == NULL) { - wpabuf_free(in_decrypted); - return 0; - } - - wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); - wpabuf_free(in_decrypted); - in_decrypted = nmsg; - } - hdr = wpabuf_mhead(in_decrypted); if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " @@ -996,11 +923,6 @@ continue_req: wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", resp); /* PEAP version changes */ - if (data->peap_version >= 2) { - resp = eap_peapv2_tlv_eap_payload(resp); - if (resp == NULL) - return -1; - } if (wpabuf_len(resp) >= 5 && wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && eap_get_type(resp) == EAP_TYPE_TLV) @@ -1091,7 +1013,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, * label, "client EAP encryption", instead. Use the old * label by default, but allow it to be configured with * phase1 parameter peaplabel=1. */ - if (data->peap_version > 1 || data->force_new_label) + if (data->force_new_label) label = "client PEAP encryption"; else label = "client EAP encryption"; diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index 267d0a5c..fef47837 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -81,6 +81,7 @@ static void * eap_pwd_init(struct eap_sm *sm) struct eap_pwd_data *data; const u8 *identity, *password; size_t identity_len, password_len; + int fragment_size; password = eap_get_config_password(sm, &password_len); if (password == NULL) { @@ -127,7 +128,11 @@ static void * eap_pwd_init(struct eap_sm *sm) data->out_frag_pos = data->in_frag_pos = 0; data->inbuf = data->outbuf = NULL; - data->mtu = 1020; /* default from RFC 5931, make it configurable! */ + fragment_size = eap_get_config_fragment_size(sm); + if (fragment_size <= 0) + data->mtu = 1020; /* default from RFC 5931 */ + else + data->mtu = fragment_size; data->state = PWD_ID_Req; diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c index fcf4712a..1ccc3523 100644 --- a/src/eap_peer/ikev2.c +++ b/src/eap_peer/ikev2.c @@ -1257,6 +1257,7 @@ static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) wpabuf_free(msg); return NULL; } + wpabuf_free(plain); data->state = IKEV2_FAILED; } else { /* HDR, N */ diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index 68253c43..defcb3c0 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -22,7 +22,6 @@ /* Maximum supported PEAP version * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt - * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt */ #define EAP_PEAP_VERSION 1 @@ -99,33 +98,6 @@ static void eap_peap_state(struct eap_peap_data *data, int state) } -static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) -{ - struct wpabuf *e; - struct eap_tlv_hdr *tlv; - - if (buf == NULL) - return NULL; - - /* Encapsulate EAP packet in EAP-Payload TLV */ - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); - e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); - if (e == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " - "for TLV encapsulation"); - wpabuf_free(buf); - return NULL; - } - tlv = wpabuf_put(e, sizeof(*tlv)); - tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - EAP_TLV_EAP_PAYLOAD_TLV); - tlv->length = host_to_be16(wpabuf_len(buf)); - wpabuf_put_buf(e, buf); - wpabuf_free(buf); - return e; -} - - static void eap_peap_req_success(struct eap_sm *sm, struct eap_peap_data *data) { @@ -239,8 +211,6 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, return NULL; } buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); - if (data->peap_version >= 2 && buf) - buf = eap_peapv2_tlv_eap_payload(buf); if (buf == NULL) return NULL; @@ -425,8 +395,6 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, len[1] = 1; tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; - if (data->peap_version >= 2) - tlv_type |= EAP_TLV_TYPE_MANDATORY; wpabuf_put_be16(buf, tlv_type); wpabuf_put_be16(buf, 56); @@ -505,8 +473,7 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) return eap_peap_build_start(sm, data, id); case PHASE1: case PHASE1_ID2: - if (data->peap_version < 2 && - tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " "starting Phase2"); eap_peap_state(data, PHASE2_START); @@ -1079,47 +1046,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm, wpabuf_free(in_decrypted); in_decrypted = nbuf; - } else if (data->peap_version >= 2) { - struct eap_tlv_hdr *tlv; - struct wpabuf *nmsg; - - if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " - "EAP TLV"); - wpabuf_free(in_decrypted); - return; - } - tlv = wpabuf_mhead(in_decrypted); - if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) != - EAP_TLV_EAP_PAYLOAD_TLV) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); - wpabuf_free(in_decrypted); - return; - } - if (sizeof(*tlv) + be_to_host16(tlv->length) > - wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " - "length"); - wpabuf_free(in_decrypted); - return; - } - hdr = (struct eap_hdr *) (tlv + 1); - if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " - "EAP packet in EAP TLV"); - wpabuf_free(in_decrypted); - return; - } - - nmsg = wpabuf_alloc(be_to_host16(hdr->length)); - if (nmsg == NULL) { - wpabuf_free(in_decrypted); - return; - } - - wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); - wpabuf_free(in_decrypted); - in_decrypted = nmsg; } hdr = wpabuf_head(in_decrypted); @@ -1168,53 +1094,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm, } -static int eap_peapv2_start_phase2(struct eap_sm *sm, - struct eap_peap_data *data) -{ - struct wpabuf *buf, *buf2; - - wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " - "payload in the same message"); - eap_peap_state(data, PHASE1_ID2); - if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY)) - return -1; - - /* TODO: which Id to use here? */ - buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6); - if (buf == NULL) - return -1; - - buf2 = eap_peapv2_tlv_eap_payload(buf); - if (buf2 == NULL) - return -1; - - wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); - - buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, - buf2); - wpabuf_free(buf2); - - if (buf == NULL) { - wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " - "data"); - return -1; - } - - wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", - buf); - - /* Append TLS data into the pending buffer after the Server Finished */ - if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) { - wpabuf_free(buf); - return -1; - } - wpabuf_put_buf(data->ssl.tls_out, buf); - wpabuf_free(buf); - - return 0; -} - - static int eap_peap_process_version(struct eap_sm *sm, void *priv, int peer_version) { @@ -1249,14 +1128,6 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv, eap_peap_state(data, FAILURE); break; } - - if (data->peap_version >= 2 && - tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - if (eap_peapv2_start_phase2(sm, data)) { - eap_peap_state(data, FAILURE); - break; - } - } break; case PHASE2_START: eap_peap_state(data, PHASE2_ID); diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c index 345c7887..45660ed7 100644 --- a/src/eap_server/eap_sim_db.c +++ b/src/eap_server/eap_sim_db.c @@ -38,7 +38,6 @@ struct eap_sim_db_pending { char imsi[20]; enum { PENDING, SUCCESS, FAILURE } state; void *cb_session_ctx; - struct os_time timestamp; int aka; union { struct { @@ -935,7 +934,6 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data, if (entry == NULL) return EAP_SIM_DB_FAILURE; - os_get_time(&entry->timestamp); os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); entry->cb_session_ctx = cb_session_ctx; entry->state = PENDING; @@ -1395,7 +1393,6 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username, if (entry == NULL) return EAP_SIM_DB_FAILURE; - os_get_time(&entry->timestamp); entry->aka = 1; os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); entry->cb_session_ctx = cb_session_ctx; diff --git a/src/eapol_auth/eapol_auth_dump.c b/src/eapol_auth/eapol_auth_dump.c index b6e0b137..6c6969b5 100644 --- a/src/eapol_auth/eapol_auth_dump.c +++ b/src/eapol_auth/eapol_auth_dump.c @@ -1,6 +1,6 @@ /* * IEEE 802.1X-2004 Authenticator - State dump - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -118,108 +118,172 @@ static inline const char * ctrl_dir_state_txt(int s) } -void eapol_auth_dump_state(FILE *f, const char *prefix, - struct eapol_state_machine *sm) +int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf, + size_t buflen) { - fprintf(f, "%sEAPOL state machine:\n", prefix); - fprintf(f, "%s aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix, - sm->aWhile, sm->quietWhile, sm->reAuthWhen); + char *pos, *end; + int ret; + + pos = buf; + end = pos + buflen; + + ret = os_snprintf(pos, end - pos, "aWhile=%d\nquietWhile=%d\n" + "reAuthWhen=%d\n", + sm->aWhile, sm->quietWhile, sm->reAuthWhen); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + #define _SB(b) ((b) ? "TRUE" : "FALSE") - fprintf(f, - "%s authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n" - "%s authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n" - "%s eapSuccess=%s eapTimeout=%s initialize=%s " - "keyAvailable=%s\n" - "%s keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n" - "%s portEnabled=%s portValid=%s reAuthenticate=%s\n", - prefix, _SB(sm->authAbort), _SB(sm->authFail), - port_state_txt(sm->authPortStatus), _SB(sm->authStart), - prefix, _SB(sm->authTimeout), _SB(sm->authSuccess), - _SB(sm->eap_if->eapFail), _SB(sm->eapolEap), - prefix, _SB(sm->eap_if->eapSuccess), - _SB(sm->eap_if->eapTimeout), - _SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable), - prefix, _SB(sm->keyDone), _SB(sm->keyRun), - _SB(sm->keyTxEnabled), port_type_txt(sm->portControl), - prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid), - _SB(sm->reAuthenticate)); - - fprintf(f, "%s Authenticator PAE:\n" - "%s state=%s\n" - "%s eapolLogoff=%s eapolStart=%s eapRestart=%s\n" - "%s portMode=%s reAuthCount=%d\n" - "%s quietPeriod=%d reAuthMax=%d\n" - "%s authEntersConnecting=%d\n" - "%s authEapLogoffsWhileConnecting=%d\n" - "%s authEntersAuthenticating=%d\n" - "%s authAuthSuccessesWhileAuthenticating=%d\n" - "%s authAuthTimeoutsWhileAuthenticating=%d\n" - "%s authAuthFailWhileAuthenticating=%d\n" - "%s authAuthEapStartsWhileAuthenticating=%d\n" - "%s authAuthEapLogoffWhileAuthenticating=%d\n" - "%s authAuthReauthsWhileAuthenticated=%d\n" - "%s authAuthEapStartsWhileAuthenticated=%d\n" - "%s authAuthEapLogoffWhileAuthenticated=%d\n", - prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix, - _SB(sm->eapolLogoff), _SB(sm->eapolStart), - _SB(sm->eap_if->eapRestart), - prefix, port_type_txt(sm->portMode), sm->reAuthCount, - prefix, sm->quietPeriod, sm->reAuthMax, - prefix, sm->authEntersConnecting, - prefix, sm->authEapLogoffsWhileConnecting, - prefix, sm->authEntersAuthenticating, - prefix, sm->authAuthSuccessesWhileAuthenticating, - prefix, sm->authAuthTimeoutsWhileAuthenticating, - prefix, sm->authAuthFailWhileAuthenticating, - prefix, sm->authAuthEapStartsWhileAuthenticating, - prefix, sm->authAuthEapLogoffWhileAuthenticating, - prefix, sm->authAuthReauthsWhileAuthenticated, - prefix, sm->authAuthEapStartsWhileAuthenticated, - prefix, sm->authAuthEapLogoffWhileAuthenticated); - - fprintf(f, "%s Backend Authentication:\n" - "%s state=%s\n" - "%s eapNoReq=%s eapReq=%s eapResp=%s\n" - "%s serverTimeout=%d\n" - "%s backendResponses=%d\n" - "%s backendAccessChallenges=%d\n" - "%s backendOtherRequestsToSupplicant=%d\n" - "%s backendAuthSuccesses=%d\n" - "%s backendAuthFails=%d\n", - prefix, prefix, - be_auth_state_txt(sm->be_auth_state), - prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq), - _SB(sm->eap_if->eapResp), - prefix, sm->serverTimeout, - prefix, sm->backendResponses, - prefix, sm->backendAccessChallenges, - prefix, sm->backendOtherRequestsToSupplicant, - prefix, sm->backendAuthSuccesses, - prefix, sm->backendAuthFails); - - fprintf(f, "%s Reauthentication Timer:\n" - "%s state=%s\n" - "%s reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix, - reauth_timer_state_txt(sm->reauth_timer_state), prefix, - sm->reAuthPeriod, _SB(sm->reAuthEnabled)); - - fprintf(f, "%s Authenticator Key Transmit:\n" - "%s state=%s\n", prefix, prefix, - auth_key_tx_state_txt(sm->auth_key_tx_state)); - - fprintf(f, "%s Key Receive:\n" - "%s state=%s\n" - "%s rxKey=%s\n", prefix, prefix, - key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey)); - - fprintf(f, "%s Controlled Directions:\n" - "%s state=%s\n" - "%s adminControlledDirections=%s " - "operControlledDirections=%s\n" - "%s operEdge=%s\n", prefix, prefix, - ctrl_dir_state_txt(sm->ctrl_dir_state), - prefix, ctrl_dir_txt(sm->adminControlledDirections), - ctrl_dir_txt(sm->operControlledDirections), - prefix, _SB(sm->operEdge)); + ret = os_snprintf(pos, end - pos, + "authAbort=%s\n" + "authFail=%s\n" + "authPortStatus=%s\n" + "authStart=%s\n" + "authTimeout=%s\n" + "authSuccess=%s\n" + "eapFail=%s\n" + "eapolEap=%s\n" + "eapSuccess=%s\n" + "eapTimeout=%s\n" + "initialize=%s\n" + "keyAvailable=%s\n" + "keyDone=%s\n" + "keyRun=%s\n" + "keyTxEnabled=%s\n" + "portControl=%s\n" + "portEnabled=%s\n" + "portValid=%s\n" + "reAuthenticate=%s\n", + _SB(sm->authAbort), + _SB(sm->authFail), + port_state_txt(sm->authPortStatus), + _SB(sm->authStart), + _SB(sm->authTimeout), + _SB(sm->authSuccess), + _SB(sm->eap_if->eapFail), + _SB(sm->eapolEap), + _SB(sm->eap_if->eapSuccess), + _SB(sm->eap_if->eapTimeout), + _SB(sm->initialize), + _SB(sm->eap_if->eapKeyAvailable), + _SB(sm->keyDone), _SB(sm->keyRun), + _SB(sm->keyTxEnabled), + port_type_txt(sm->portControl), + _SB(sm->eap_if->portEnabled), + _SB(sm->portValid), + _SB(sm->reAuthenticate)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "auth_pae_state=%s\n" + "eapolLogoff=%s\n" + "eapolStart=%s\n" + "eapRestart=%s\n" + "portMode=%s\n" + "reAuthCount=%d\n" + "quietPeriod=%d\n" + "reAuthMax=%d\n" + "authEntersConnecting=%d\n" + "authEapLogoffsWhileConnecting=%d\n" + "authEntersAuthenticating=%d\n" + "authAuthSuccessesWhileAuthenticating=%d\n" + "authAuthTimeoutsWhileAuthenticating=%d\n" + "authAuthFailWhileAuthenticating=%d\n" + "authAuthEapStartsWhileAuthenticating=%d\n" + "authAuthEapLogoffWhileAuthenticating=%d\n" + "authAuthReauthsWhileAuthenticated=%d\n" + "authAuthEapStartsWhileAuthenticated=%d\n" + "authAuthEapLogoffWhileAuthenticated=%d\n", + auth_pae_state_txt(sm->auth_pae_state), + _SB(sm->eapolLogoff), + _SB(sm->eapolStart), + _SB(sm->eap_if->eapRestart), + port_type_txt(sm->portMode), + sm->reAuthCount, + sm->quietPeriod, sm->reAuthMax, + sm->authEntersConnecting, + sm->authEapLogoffsWhileConnecting, + sm->authEntersAuthenticating, + sm->authAuthSuccessesWhileAuthenticating, + sm->authAuthTimeoutsWhileAuthenticating, + sm->authAuthFailWhileAuthenticating, + sm->authAuthEapStartsWhileAuthenticating, + sm->authAuthEapLogoffWhileAuthenticating, + sm->authAuthReauthsWhileAuthenticated, + sm->authAuthEapStartsWhileAuthenticated, + sm->authAuthEapLogoffWhileAuthenticated); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "be_auth_state=%s\n" + "eapNoReq=%s\n" + "eapReq=%s\n" + "eapResp=%s\n" + "serverTimeout=%d\n" + "backendResponses=%d\n" + "backendAccessChallenges=%d\n" + "backendOtherRequestsToSupplicant=%d\n" + "backendAuthSuccesses=%d\n" + "backendAuthFails=%d\n", + be_auth_state_txt(sm->be_auth_state), + _SB(sm->eap_if->eapNoReq), + _SB(sm->eap_if->eapReq), + _SB(sm->eap_if->eapResp), + sm->serverTimeout, + sm->backendResponses, + sm->backendAccessChallenges, + sm->backendOtherRequestsToSupplicant, + sm->backendAuthSuccesses, + sm->backendAuthFails); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "reauth_timer_state=%s\n" + "reAuthPeriod=%d\n" + "reAuthEnabled=%s\n", + reauth_timer_state_txt(sm->reauth_timer_state), + sm->reAuthPeriod, + _SB(sm->reAuthEnabled)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "auth_key_tx_state=%s\n", + auth_key_tx_state_txt(sm->auth_key_tx_state)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "key_rx_state=%s\n" + "rxKey=%s\n", + key_rx_state_txt(sm->key_rx_state), + _SB(sm->rxKey)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, + "ctrl_dir_state=%s\n" + "adminControlledDirections=%s\n" + "operControlledDirections=%s\n" + "operEdge=%s\n", + ctrl_dir_state_txt(sm->ctrl_dir_state), + ctrl_dir_txt(sm->adminControlledDirections), + ctrl_dir_txt(sm->operControlledDirections), + _SB(sm->operEdge)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; #undef _SB + + return pos - buf; } diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h index 3a0f4509..f0ff4644 100644 --- a/src/eapol_auth/eapol_auth_sm.h +++ b/src/eapol_auth/eapol_auth_sm.h @@ -83,8 +83,8 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, const char *identity, const char *radius_cui); void eapol_auth_free(struct eapol_state_machine *sm); void eapol_auth_step(struct eapol_state_machine *sm); -void eapol_auth_dump_state(FILE *f, const char *prefix, - struct eapol_state_machine *sm); +int eapol_auth_dump_state(struct eapol_state_machine *sm, char *buf, + size_t buflen); int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx); #endif /* EAPOL_AUTH_SM_H */ diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index 9d7aef04..05b9851f 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -137,6 +137,9 @@ struct eapol_sm { Boolean cached_pmk; Boolean unicast_key_received, broadcast_key_received; + + Boolean force_authorized_update; + #ifdef CONFIG_EAP_PROXY Boolean use_eap_proxy; struct eap_proxy_sm *eap_proxy; @@ -210,7 +213,6 @@ SM_STATE(SUPP_PAE, LOGOFF) SM_ENTRY(SUPP_PAE, LOGOFF); eapol_sm_txLogoff(sm); sm->logoffSent = TRUE; - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); } @@ -221,7 +223,6 @@ SM_STATE(SUPP_PAE, DISCONNECTED) sm->sPortMode = Auto; sm->startCount = 0; sm->logoffSent = FALSE; - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); sm->suppAbort = TRUE; @@ -286,7 +287,6 @@ SM_STATE(SUPP_PAE, HELD) SM_ENTRY(SUPP_PAE, HELD); sm->heldWhile = sm->heldPeriod; eapol_enable_timer_tick(sm); - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); sm->cb_status = EAPOL_CB_FAILURE; } @@ -295,7 +295,6 @@ SM_STATE(SUPP_PAE, HELD) SM_STATE(SUPP_PAE, AUTHENTICATED) { SM_ENTRY(SUPP_PAE, AUTHENTICATED); - sm->suppPortStatus = Authorized; eapol_sm_set_port_authorized(sm); sm->cb_status = EAPOL_CB_SUCCESS; } @@ -311,7 +310,6 @@ SM_STATE(SUPP_PAE, RESTART) SM_STATE(SUPP_PAE, S_FORCE_AUTH) { SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); - sm->suppPortStatus = Authorized; eapol_sm_set_port_authorized(sm); sm->sPortMode = ForceAuthorized; } @@ -320,7 +318,6 @@ SM_STATE(SUPP_PAE, S_FORCE_AUTH) SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) { SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); sm->sPortMode = ForceUnauthorized; eapol_sm_txLogoff(sm); @@ -879,14 +876,24 @@ static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) static void eapol_sm_set_port_authorized(struct eapol_sm *sm) { - if (sm->ctx->port_cb) + int cb; + + cb = sm->suppPortStatus != Authorized || sm->force_authorized_update; + sm->force_authorized_update = FALSE; + sm->suppPortStatus = Authorized; + if (cb && sm->ctx->port_cb) sm->ctx->port_cb(sm->ctx->ctx, 1); } static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm) { - if (sm->ctx->port_cb) + int cb; + + cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update; + sm->force_authorized_update = FALSE; + sm->suppPortStatus = Unauthorized; + if (cb && sm->ctx->port_cb) sm->ctx->port_cb(sm->ctx->ctx, 0); } @@ -1370,6 +1377,8 @@ void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled) return; wpa_printf(MSG_DEBUG, "EAPOL: External notification - " "portEnabled=%d", enabled); + if (sm->portEnabled != enabled) + sm->force_authorized_update = TRUE; sm->portEnabled = enabled; eapol_sm_step(sm); } @@ -1608,7 +1617,6 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm) return; sm->cached_pmk = FALSE; sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; - sm->suppPortStatus = Unauthorized; eapol_sm_set_port_unauthorized(sm); /* Make sure we do not start sending EAPOL-Start frames first, but @@ -2002,6 +2010,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) #endif /* CONFIG_EAP_PROXY */ /* Initialize EAPOL state machines */ + sm->force_authorized_update = TRUE; sm->initialize = TRUE; eapol_sm_step(sm); sm->initialize = FALSE; diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index e77563bb..61cafe43 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -78,10 +78,10 @@ int p2p_connection_in_progress(struct p2p_data *p2p) static void p2p_expire_peers(struct p2p_data *p2p) { struct p2p_device *dev, *n; - struct os_time now; + struct os_reltime now; size_t i; - os_get_time(&now); + os_get_reltime(&now); dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) { if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec) continue; @@ -93,7 +93,7 @@ static void p2p_expire_peers(struct p2p_data *p2p) * We are connected as a client to a group in which the * peer is the GO, so do not expire the peer entry. */ - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); continue; } @@ -107,7 +107,7 @@ static void p2p_expire_peers(struct p2p_data *p2p) * The peer is connected as a client in a group where * we are the GO, so do not expire the peer entry. */ - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); continue; } @@ -170,10 +170,6 @@ static const char * p2p_state_txt(int state) return "INVITE"; case P2P_INVITE_LISTEN: return "INVITE_LISTEN"; - case P2P_SEARCH_WHEN_READY: - return "SEARCH_WHEN_READY"; - case P2P_CONTINUE_SEARCH_WHEN_READY: - return "CONTINUE_SEARCH_WHEN_READY"; default: return "?"; } @@ -420,7 +416,7 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p, dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { count++; if (oldest == NULL || - os_time_before(&dev->last_seen, &oldest->last_seen)) + os_reltime_before(&dev->last_seen, &oldest->last_seen)) oldest = dev; } if (count + 1 > p2p->cfg->max_peers && oldest) { @@ -528,7 +524,7 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, os_memcpy(dev->interface_addr, cli->p2p_interface_addr, ETH_ALEN); - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN); os_memcpy(dev->member_in_go_iface, go_interface_addr, ETH_ALEN); @@ -644,14 +640,14 @@ static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev, * Info attributes. */ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len, int scan_res) { struct p2p_device *dev; struct p2p_message msg; const u8 *p2p_dev_addr; int i; - struct os_time time_now; + struct os_reltime time_now; os_memset(&msg, 0, sizeof(msg)); if (p2p_parse_ies(ies, ies_len, &msg)) { @@ -685,7 +681,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, } if (rx_time == NULL) { - os_get_time(&time_now); + os_get_reltime(&time_now); rx_time = &time_now; } @@ -694,7 +690,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, * entry is newer than the one previously stored. */ if (dev->last_seen.sec > 0 && - os_time_before(rx_time, &dev->last_seen)) { + os_reltime_before(rx_time, &dev->last_seen)) { p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)", (unsigned int) rx_time->sec, (unsigned int) rx_time->usec, @@ -704,7 +700,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, return -1; } - os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_time)); + os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime)); dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY); @@ -932,9 +928,6 @@ static void p2p_search(struct p2p_data *p2p) if (res < 0) { p2p_dbg(p2p, "Scan request failed"); p2p_continue_find(p2p); - } else if (res == 1) { - p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes"); - p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY); } else { p2p_dbg(p2p, "Running p2p_scan"); p2p->p2p_scan_running = 1; @@ -1038,7 +1031,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, int res; p2p_dbg(p2p, "Starting find (type=%d)", type); - os_get_time(&p2p->find_start); + os_get_reltime(&p2p->find_start); if (p2p->p2p_scan_running) { p2p_dbg(p2p, "p2p_scan is already running"); } @@ -1097,11 +1090,9 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout, p2p, NULL); - } else if (res == 1) { - p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes"); - res = 0; - p2p_set_state(p2p, P2P_SEARCH_WHEN_READY); - eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); + } else if (p2p->p2p_scan_running) { + p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running"); + /* wait for the previous p2p_scan to complete */ } else { p2p_dbg(p2p, "Failed to start p2p_scan"); p2p_set_state(p2p, P2P_IDLE); @@ -1112,34 +1103,12 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, } -int p2p_other_scan_completed(struct p2p_data *p2p) -{ - if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) { - p2p_set_state(p2p, P2P_SEARCH); - p2p_search(p2p); - return 1; - } - if (p2p->state != P2P_SEARCH_WHEN_READY) - return 0; - p2p_dbg(p2p, "Starting pending P2P find now that previous scan was completed"); - if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type, - p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id, p2p->search_delay) < 0) { - p2p->cfg->find_stopped(p2p->cfg->cb_ctx); - return 0; - } - return 1; -} - - void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) { p2p_dbg(p2p, "Stopping find"); eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); p2p_clear_timeout(p2p); - if (p2p->state == P2P_SEARCH || - p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY || - p2p->state == P2P_SEARCH_WHEN_READY) + if (p2p->state == P2P_SEARCH) p2p->cfg->find_stopped(p2p->cfg->cb_ctx); p2p_set_state(p2p, P2P_IDLE); p2p_free_req_dev_types(p2p); @@ -1527,7 +1496,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, struct p2p_device *dev, struct p2p_message *msg) { - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); p2p_copy_wps_info(p2p, dev, 0, msg); @@ -1866,7 +1835,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, if (dev) { if (dev->country[0] == 0 && msg.listen_channel) os_memcpy(dev->country, msg.listen_channel, 3); - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); p2p_parse_free(&msg); return; /* already known */ } @@ -1877,7 +1846,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, return; } - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); dev->flags |= P2P_DEV_PROBE_REQ_ONLY; if (msg.listen_channel) { @@ -1911,7 +1880,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, dev = p2p_get_device(p2p, addr); if (dev) { - os_get_time(&dev->last_seen); + os_get_reltime(&dev->last_seen); return dev; /* already known */ } @@ -2868,10 +2837,10 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success) int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len) { - if (os_time_before(rx_time, &p2p->find_start)) { + if (os_reltime_before(rx_time, &p2p->find_start)) { /* * The driver may have cached (e.g., in cfg80211 BSS table) the * scan results for relatively long time. To avoid reporting @@ -3467,10 +3436,6 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) case P2P_INVITE_LISTEN: p2p_timeout_invite_listen(p2p); break; - case P2P_SEARCH_WHEN_READY: - break; - case P2P_CONTINUE_SEARCH_WHEN_READY: - break; } } @@ -3553,7 +3518,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info, struct p2p_device *dev; int res; char *pos, *end; - struct os_time now; + struct os_reltime now; if (info == NULL) return -1; @@ -3564,7 +3529,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info, pos = buf; end = buf + buflen; - os_get_time(&now); + os_get_reltime(&now); res = os_snprintf(pos, end - pos, "age=%d\n" "listen_freq=%d\n" @@ -3868,6 +3833,11 @@ static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da, return; } + if (p2p->cfg->presence_resp) { + p2p->cfg->presence_resp(p2p->cfg->cb_ctx, sa, *msg.status, + msg.noa, msg.noa_len); + } + if (*msg.status) { p2p_dbg(p2p, "P2P Presence Request was rejected: status %u", *msg.status); @@ -4276,8 +4246,7 @@ int p2p_in_progress(struct p2p_data *p2p) { if (p2p == NULL) return 0; - if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY || - p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) + if (p2p->state == P2P_SEARCH) return 2; return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING; } @@ -4293,13 +4262,6 @@ void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, } -void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay) -{ - if (p2p && p2p->search_delay < delay) - p2p->search_delay = delay; -} - - #ifdef CONFIG_WIFI_DISPLAY static void p2p_update_wfd_ie_groups(struct p2p_data *p2p) diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 22d0c580..25a91e77 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -778,6 +778,17 @@ struct p2p_config { * or 0 if not. */ int (*go_connected)(void *ctx, const u8 *dev_addr); + + /** + * presence_resp - Callback on Presence Response + * @ctx: Callback context from cb_ctx + * @src: Source address (GO's P2P Interface Address) + * @status: Result of the request (P2P_SC_*) + * @noa: Returned NoA value + * @noa_len: Length of the NoA buffer in octets + */ + void (*presence_resp)(void *ctx, const u8 *src, u8 status, + const u8 *noa, size_t noa_len); }; @@ -1245,7 +1256,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, * start of a pending operation, e.g., to start a pending GO negotiation. */ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len); /** @@ -1815,13 +1826,6 @@ int p2p_set_no_go_freq(struct p2p_data *p2p, */ int p2p_in_progress(struct p2p_data *p2p); -/** - * p2p_other_scan_completed - Notify completion of non-P2P scan - * @p2p: P2P module context from p2p_init() - * Returns: 0 if P2P module is idle or 1 if an operation was started - */ -int p2p_other_scan_completed(struct p2p_data *p2p); - const char * p2p_wps_method_text(enum p2p_wps_method method); /** @@ -1833,8 +1837,6 @@ const char * p2p_wps_method_text(enum p2p_wps_method method); void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, u8 client_timeout); -void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay); - int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie); int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie); int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie); diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 008651e4..0e688a96 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -1040,6 +1040,7 @@ fail: wpabuf_head(conf), wpabuf_len(conf), 0) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); p2p_go_neg_failed(p2p, dev, -1); + p2p->cfg->send_action_done(p2p->cfg->cb_ctx); } wpabuf_free(conf); if (status != P2P_SC_SUCCESS) { diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index e980be68..fef223f7 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -23,7 +23,7 @@ enum p2p_go_state { */ struct p2p_device { struct dl_list list; - struct os_time last_seen; + struct os_reltime last_seen; int listen_freq; enum p2p_wps_method wps_method; @@ -205,16 +205,6 @@ struct p2p_data { * P2P_INVITE_LISTEN - Listen during Invite */ P2P_INVITE_LISTEN, - - /** - * P2P_SEARCH_WHEN_READY - Waiting to start Search - */ - P2P_SEARCH_WHEN_READY, - - /** - * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search - */ - P2P_CONTINUE_SEARCH_WHEN_READY, } state; /** @@ -403,7 +393,7 @@ struct p2p_data { u8 *find_dev_id; u8 find_dev_id_buf[ETH_ALEN]; - struct os_time find_start; /* time of last p2p_find start */ + struct os_reltime find_start; /* time of last p2p_find start */ struct p2p_group **groups; size_t num_groups; @@ -726,7 +716,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, struct p2p_device *dev, struct p2p_message *msg); int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, - struct os_time *rx_time, int level, const u8 *ies, + struct os_reltime *rx_time, int level, const u8 *ies, size_t ies_len, int scan_res); struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr); struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index 290c7c81..76259966 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -122,7 +122,7 @@ struct radius_msg_list { /** * last_attempt - Time of the last transmission attempt */ - struct os_time last_attempt; + struct os_reltime last_attempt; /** * shared_secret - Shared secret with the target RADIUS server @@ -351,7 +351,7 @@ static int radius_client_retransmit(struct radius_client_data *radius, HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", radius_msg_get_hdr(entry->msg)->identifier); - os_get_time(&entry->last_attempt); + os_get_reltime(&entry->last_attempt); buf = radius_msg_get_buf(entry->msg); if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) radius_client_handle_send_error(radius, s, entry->msg_type); @@ -373,7 +373,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) { struct radius_client_data *radius = eloop_ctx; struct hostapd_radius_servers *conf = radius->conf; - struct os_time now; + struct os_reltime now; os_time_t first; struct radius_msg_list *entry, *prev, *tmp; int auth_failover = 0, acct_failover = 0; @@ -383,7 +383,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) if (!entry) return; - os_get_time(&now); + os_get_reltime(&now); first = 0; prev = NULL; @@ -481,7 +481,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) static void radius_client_update_timeout(struct radius_client_data *radius) { - struct os_time now; + struct os_reltime now; os_time_t first; struct radius_msg_list *entry; @@ -497,7 +497,7 @@ static void radius_client_update_timeout(struct radius_client_data *radius) first = entry->next_try; } - os_get_time(&now); + os_get_reltime(&now); if (first < now.sec) first = now.sec; eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius, @@ -536,7 +536,7 @@ static void radius_client_list_add(struct radius_client_data *radius, entry->msg_type = msg_type; entry->shared_secret = shared_secret; entry->shared_secret_len = shared_secret_len; - os_get_time(&entry->last_attempt); + os_get_reltime(&entry->last_attempt); entry->first_try = entry->last_attempt.sec; entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; entry->attempts = 1; @@ -692,7 +692,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) struct radius_rx_handler *handlers; size_t num_handlers, i; struct radius_msg_list *req, *prev_req; - struct os_time now; + struct os_reltime now; struct hostapd_radius_server *rconf; int invalid_authenticator = 0; @@ -772,7 +772,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) goto fail; } - os_get_time(&now); + os_get_reltime(&now); roundtrip = (now.sec - req->last_attempt.sec) * 100 + (now.usec - req->last_attempt.usec) / 10000; hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c index 418b1605..b2a27735 100644 --- a/src/radius/radius_das.c +++ b/src/radius/radius_das.c @@ -16,9 +16,6 @@ #include "radius_das.h" -extern int wpa_debug_level; - - struct radius_das_data { int sock; u8 *shared_secret; diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index fe197704..1063d65a 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -244,7 +244,7 @@ struct radius_server_data { /** * start_time - Timestamp of server start */ - struct os_time start_time; + struct os_reltime start_time; /** * counters - Statistics counters for server operations @@ -298,8 +298,6 @@ struct radius_server_data { }; -extern int wpa_debug_level; - #define RADIUS_DEBUG(args...) \ wpa_printf(MSG_DEBUG, "RADIUS SRV: " args) #define RADIUS_ERROR(args...) \ @@ -1261,7 +1259,7 @@ radius_server_init(struct radius_server_conf *conf) if (data == NULL) return NULL; - os_get_time(&data->start_time); + os_get_reltime(&data->start_time); data->conf_ctx = conf->conf_ctx; data->eap_sim_db_priv = conf->eap_sim_db_priv; data->ssl_ctx = conf->ssl_ctx; @@ -1375,7 +1373,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, int ret, uptime; unsigned int idx; char *end, *pos; - struct os_time now; + struct os_reltime now; struct radius_client *cli; /* RFC 2619 - RADIUS Authentication Server MIB */ @@ -1386,7 +1384,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, pos = buf; end = buf + buflen; - os_get_time(&now); + os_get_reltime(&now); uptime = (now.sec - data->start_time.sec) * 100 + ((now.usec - data->start_time.usec) / 10000) % 100; ret = os_snprintf(pos, end - pos, diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c index 789ac255..cb86dfbc 100644 --- a/src/rsn_supp/peerkey.c +++ b/src/rsn_supp/peerkey.c @@ -516,7 +516,6 @@ static int wpa_supplicant_process_smk_m45( struct wpa_peerkey *peerkey; struct wpa_eapol_ie_parse kde; u32 lifetime; - struct os_time now; if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " @@ -568,10 +567,8 @@ static int wpa_supplicant_process_smk_m45( lifetime = WPA_GET_BE32(kde.lifetime); wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime); if (lifetime > 1000000000) - lifetime = 1000000000; /* avoid overflowing expiration time */ + lifetime = 1000000000; /* avoid overflowing eloop time */ peerkey->lifetime = lifetime; - os_get_time(&now); - peerkey->expiration = now.sec + lifetime; eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, sm, peerkey); @@ -736,7 +733,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, struct wpa_eapol_ie_parse *kde) { u32 lifetime; - struct os_time now; if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime)) return; @@ -755,8 +751,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, lifetime, peerkey->lifetime); peerkey->lifetime = lifetime; - os_get_time(&now); - peerkey->expiration = now.sec + lifetime; eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, sm, peerkey); @@ -1116,7 +1110,7 @@ void peerkey_deinit(struct wpa_sm *sm) while (peerkey) { prev = peerkey; peerkey = peerkey->next; - os_free(prev); + wpa_supplicant_peerkey_free(sm, prev); } sm->peerkey = NULL; } diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h index b8845f71..f420691a 100644 --- a/src/rsn_supp/peerkey.h +++ b/src/rsn_supp/peerkey.h @@ -24,7 +24,6 @@ struct wpa_peerkey { int smk_complete; u8 smkid[PMKID_LEN]; u32 lifetime; - os_time_t expiration; int cipher; /* Selected cipher (WPA_CIPHER_*) */ u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; int replay_counter_set; diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index 33fa1a29..09608153 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -53,9 +53,9 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) { struct rsn_pmksa_cache *pmksa = eloop_ctx; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; pmksa->pmksa = entry->next; @@ -80,13 +80,13 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) { int sec; struct rsn_pmksa_cache_entry *entry; - struct os_time now; + struct os_reltime now; eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); if (pmksa->pmksa == NULL) return; - os_get_time(&now); + os_get_reltime(&now); sec = pmksa->pmksa->expiration - now.sec; if (sec < 0) sec = 0; @@ -125,7 +125,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp) { struct rsn_pmksa_cache_entry *entry, *pos, *prev; - struct os_time now; + struct os_reltime now; if (pmk_len > PMK_LEN) return NULL; @@ -137,7 +137,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, entry->pmk_len = pmk_len; rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, wpa_key_mgmt_sha256(akmp)); - os_get_time(&now); + os_get_reltime(&now); entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; @@ -466,9 +466,9 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) int i, ret; char *pos = buf; struct rsn_pmksa_cache_entry *entry; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); ret = os_snprintf(pos, buf + len - pos, "Index / AA / PMKID / expiration (in seconds) / " "opportunistic\n"); diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index d4f86e6f..a294730d 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -688,10 +688,11 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, os_memcpy(gd.gtk, gtk, gtk_len); gd.gtk_len = gtk_len; - if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, - gtk_len, gtk_len, - &gd.key_rsc_len, &gd.alg) || - wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) { + if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED && + (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, + gtk_len, gtk_len, + &gd.key_rsc_len, &gd.alg) || + wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Failed to install GTK"); return -1; @@ -1112,7 +1113,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, } wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); - if (ie.gtk && + if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) { + wpa_supplicant_key_neg_complete(sm, sm->bssid, + key_info & WPA_KEY_INFO_SECURE); + } else if (ie.gtk && wpa_supplicant_pairwise_gtk(sm, key, ie.gtk, ie.gtk_len, key_info) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, @@ -2094,6 +2098,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) */ void wpa_sm_notify_disassoc(struct wpa_sm *sm) { + peerkey_deinit(sm); rsn_preauth_deinit(sm); pmksa_cache_clear_current(sm); if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE) @@ -2705,3 +2710,24 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) return 0; } #endif /* CONFIG_WNM */ + + +#ifdef CONFIG_PEERKEY +int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, + const u8 *buf, size_t len) +{ + struct wpa_peerkey *peerkey; + + for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { + if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0) + break; + } + + if (!peerkey) + return 0; + + wpa_sm_rx_eapol(sm, src_addr, buf, len); + + return 1; +} +#endif /* CONFIG_PEERKEY */ diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index db7f0db8..e189a585 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -306,11 +306,19 @@ static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, #ifdef CONFIG_PEERKEY int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer); +int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, + const u8 *buf, size_t len); #else /* CONFIG_PEERKEY */ static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) { return -1; } + +static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr, + const u8 *buf, size_t len) +{ + return 0; +} #endif /* CONFIG_PEERKEY */ #ifdef CONFIG_IEEE80211R diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 3a40c96f..c8d8cfc8 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -207,6 +207,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); + else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE) + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); else { wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", sm->key_mgmt); @@ -400,8 +402,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, } } - if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { + if (!wpa_key_mgmt_ft(sm->key_mgmt)) { wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " "enabled for this connection"); return -1; @@ -526,8 +527,7 @@ int wpa_ft_is_completed(struct wpa_sm *sm) if (sm == NULL) return 0; - if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) + if (!wpa_key_mgmt_ft(sm->key_mgmt)) return 0; return sm->ft_completed; @@ -678,8 +678,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); - if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { + if (!wpa_key_mgmt_ft(sm->key_mgmt)) { wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " "enabled for this connection"); return -1; diff --git a/src/utils/common.c b/src/utils/common.c index 257bb6d4..39751d40 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -735,3 +735,95 @@ char * freq_range_list_str(const struct wpa_freq_range_list *list) return buf; } + + +int int_array_len(const int *a) +{ + int i; + for (i = 0; a && a[i]; i++) + ; + return i; +} + + +void int_array_concat(int **res, const int *a) +{ + int reslen, alen, i; + int *n; + + reslen = int_array_len(*res); + alen = int_array_len(a); + + n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); + if (n == NULL) { + os_free(*res); + *res = NULL; + return; + } + for (i = 0; i <= alen; i++) + n[reslen + i] = a[i]; + *res = n; +} + + +static int freq_cmp(const void *a, const void *b) +{ + int _a = *(int *) a; + int _b = *(int *) b; + + if (_a == 0) + return 1; + if (_b == 0) + return -1; + return _a - _b; +} + + +void int_array_sort_unique(int *a) +{ + int alen; + int i, j; + + if (a == NULL) + return; + + alen = int_array_len(a); + qsort(a, alen, sizeof(int), freq_cmp); + + i = 0; + j = 1; + while (a[i] && a[j]) { + if (a[i] == a[j]) { + j++; + continue; + } + a[++i] = a[j++]; + } + if (a[i]) + i++; + a[i] = 0; +} + + +void int_array_add_unique(int **res, int a) +{ + int reslen; + int *n; + + for (reslen = 0; *res && (*res)[reslen]; reslen++) { + if ((*res)[reslen] == a) + return; /* already in the list */ + } + + n = os_realloc_array(*res, reslen + 2, sizeof(int)); + if (n == NULL) { + os_free(*res); + *res = NULL; + return; + } + + n[reslen] = a; + n[reslen + 1] = 0; + + *res = n; +} diff --git a/src/utils/common.h b/src/utils/common.h index 028a5eff..a85cc159 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -459,6 +459,14 @@ typedef u64 __bitwise le64; #endif /* __GNUC__ */ #endif /* __must_check */ +#ifndef __maybe_unused +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __maybe_unused __attribute__((unused)) +#else +#define __maybe_unused +#endif /* __GNUC__ */ +#endif /* __must_check */ + int hwaddr_aton(const char *txt, u8 *addr); int hwaddr_compact_aton(const char *txt, u8 *addr); int hwaddr_aton2(const char *txt, u8 *addr); @@ -519,6 +527,11 @@ int freq_range_list_includes(const struct wpa_freq_range_list *list, unsigned int freq); char * freq_range_list_str(const struct wpa_freq_range_list *list); +int int_array_len(const int *a); +void int_array_concat(int **res, const int *a); +void int_array_sort_unique(int *a); +void int_array_add_unique(int **res, int a); + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) diff --git a/src/utils/eloop.c b/src/utils/eloop.c index e983edcf..f83a2327 100644 --- a/src/utils/eloop.c +++ b/src/utils/eloop.c @@ -623,10 +623,11 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } @@ -654,10 +655,11 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } diff --git a/src/utils/eloop.h b/src/utils/eloop.h index d3980fa4..07b8c0dc 100644 --- a/src/utils/eloop.h +++ b/src/utils/eloop.h @@ -229,7 +229,8 @@ int eloop_is_timeout_registered(eloop_timeout_handler handler, * @handler: Matching callback function * @eloop_data: Matching eloop_data * @user_data: Matching user_data - * Returns: 1 if the timeout is depleted, 0 if no change is made + * Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no + * timeout matched * * Find a registered matching <handler,eloop_data,user_data> timeout. If found, * deplete the timeout if remaining time is more than the requested time. @@ -245,7 +246,8 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, * @handler: Matching callback function * @eloop_data: Matching eloop_data * @user_data: Matching user_data - * Returns: 1 if the timeout is replenished, 0 if no change is made + * Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no + * timeout matched * * Find a registered matching <handler,eloop_data,user_data> timeout. If found, * replenish the timeout if remaining time is less than the requested time. diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c index a1f99964..de47fb21 100644 --- a/src/utils/eloop_win.c +++ b/src/utils/eloop_win.c @@ -378,10 +378,11 @@ int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } @@ -409,10 +410,11 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, user_data); return 1; } + return 0; } } - return 0; + return -1; } diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 38ea8aa3..7846c1e5 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -375,19 +375,19 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, #endif /* CONFIG_ANDROID_LOG */ } -void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) +void wpa_hexdump(int level, const char *title, const void *buf, size_t len) { _wpa_hexdump(level, title, buf, len, 1); } -void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) +void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len) { _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); } -static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, +static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len, int show) { size_t i, llen; @@ -407,7 +407,7 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, /* can do ascii processing in userspace */ for (i = 0; i < len; i++) fprintf(wpa_debug_tracing_file, - " %02x", buf[i]); + " %02x", pos[i]); } fflush(wpa_debug_tracing_file); } @@ -495,13 +495,14 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, } -void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) +void wpa_hexdump_ascii(int level, const char *title, const void *buf, + size_t len) { _wpa_hexdump_ascii(level, title, buf, len, 1); } -void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, +void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, size_t len) { _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h index 2ed1bd8e..50e8ae9d 100644 --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h @@ -11,6 +11,10 @@ #include "wpabuf.h" +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + /* Debugging function - conditional printf and hex dump. Driver wrappers can * use these for debugging purposes. */ @@ -77,7 +81,7 @@ PRINTF_FORMAT(2, 3); * output may be directed to stdout, stderr, and/or syslog based on * configuration. The contents of buf is printed out has hex dump. */ -void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); +void wpa_hexdump(int level, const char *title, const void *buf, size_t len); static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) @@ -99,7 +103,7 @@ static inline void wpa_hexdump_buf(int level, const char *title, * like wpa_hexdump(), but by default, does not include secret keys (passwords, * etc.) in debug output. */ -void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); +void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len); static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) @@ -121,7 +125,7 @@ static inline void wpa_hexdump_buf_key(int level, const char *title, * the hex numbers and ASCII characters (for printable range) are shown. 16 * bytes per line will be shown. */ -void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, +void wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len); /** @@ -138,7 +142,7 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by * default, does not include secret keys (passwords, etc.) in debug output. */ -void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, +void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, size_t len); /* diff --git a/src/wps/httpread.c b/src/wps/httpread.c index ad4f4a1d..b51d9757 100644 --- a/src/wps/httpread.c +++ b/src/wps/httpread.c @@ -67,8 +67,6 @@ struct httpread { int timeout_seconds; /* 0 or total duration timeout period */ /* dynamically used information follows */ - int sd_registered; /* nonzero if we need to unregister socket */ - int to_registered; /* nonzero if we need to unregister timeout */ int got_hdr; /* nonzero when header is finalized */ char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */ @@ -129,19 +127,6 @@ static int word_eq(char *s1, char *s2) } -/* convert hex to binary - * Requires that c have been previously tested true with isxdigit(). - */ -static int hex_value(int c) -{ - if (isdigit(c)) - return c - '0'; - if (islower(c)) - return 10 + c - 'a'; - return 10 + c - 'A'; -} - - static void httpread_timeout_handler(void *eloop_data, void *user_ctx); /* httpread_destroy -- if h is non-NULL, clean up @@ -156,12 +141,8 @@ void httpread_destroy(struct httpread *h) if (!h) return; - if (h->to_registered) - eloop_cancel_timeout(httpread_timeout_handler, NULL, h); - h->to_registered = 0; - if (h->sd_registered) - eloop_unregister_sock(h->sd, EVENT_TYPE_READ); - h->sd_registered = 0; + eloop_cancel_timeout(httpread_timeout_handler, NULL, h); + eloop_unregister_sock(h->sd, EVENT_TYPE_READ); os_free(h->body); os_free(h->uri); os_memset(h, 0, sizeof(*h)); /* aid debugging */ @@ -176,7 +157,6 @@ static void httpread_timeout_handler(void *eloop_data, void *user_ctx) { struct httpread *h = user_ctx; wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h); - h->to_registered = 0; /* is self-cancelling */ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT); } @@ -295,8 +275,7 @@ static int httpread_hdr_analyze(struct httpread *h) int c = *rawuri; if (c == '%' && isxdigit(rawuri[1]) && isxdigit(rawuri[2])) { - *uri++ = (hex_value(rawuri[1]) << 4) | - hex_value(rawuri[2]); + *uri++ = hex2byte(rawuri + 1); rawuri += 3; } else { *uri++ = c; @@ -703,15 +682,11 @@ got_file: * and just in case somehow we don't get destroyed right away, * unregister now. */ - if (h->sd_registered) - eloop_unregister_sock(h->sd, EVENT_TYPE_READ); - h->sd_registered = 0; + eloop_unregister_sock(h->sd, EVENT_TYPE_READ); /* The application can destroy us whenever they feel like... * cancel timeout. */ - if (h->to_registered) - eloop_cancel_timeout(httpread_timeout_handler, NULL, h); - h->to_registered = 0; + eloop_cancel_timeout(httpread_timeout_handler, NULL, h); (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY); } @@ -749,21 +724,17 @@ struct httpread * httpread_create( h->max_bytes = max_bytes; h->timeout_seconds = timeout_seconds; - if (timeout_seconds > 0) { - if (eloop_register_timeout(timeout_seconds, 0, - httpread_timeout_handler, - NULL, h)) { - /* No way to recover (from malloc failure) */ - goto fail; - } - h->to_registered = 1; + if (timeout_seconds > 0 && + eloop_register_timeout(timeout_seconds, 0, + httpread_timeout_handler, NULL, h)) { + /* No way to recover (from malloc failure) */ + goto fail; } if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler, NULL, h)) { /* No way to recover (from malloc failure) */ goto fail; } - h->sd_registered = 1; return h; fail: diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c index b2327544..336246ea 100644 --- a/src/wps/wps_attr_build.c +++ b/src/wps/wps_attr_build.c @@ -201,6 +201,11 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, #ifdef CONFIG_WPS2 u8 *len; +#ifdef CONFIG_WPS_TESTING + if (WPS_VERSION == 0x10) + return 0; +#endif /* CONFIG_WPS_TESTING */ + if (wpabuf_tailroom(msg) < 7 + 3 + (req_to_enroll ? 3 : 0) + (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0)) diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c index 1b12b5a1..fe736f32 100644 --- a/src/wps/wps_dev_attr.c +++ b/src/wps/wps_dev_attr.c @@ -409,25 +409,6 @@ int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands) } -void wps_device_data_dup(struct wps_device_data *dst, - const struct wps_device_data *src) -{ - if (src->device_name) - dst->device_name = os_strdup(src->device_name); - if (src->manufacturer) - dst->manufacturer = os_strdup(src->manufacturer); - if (src->model_name) - dst->model_name = os_strdup(src->model_name); - if (src->model_number) - dst->model_number = os_strdup(src->model_number); - if (src->serial_number) - dst->serial_number = os_strdup(src->serial_number); - os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN); - dst->os_version = src->os_version; - dst->rf_bands = src->rf_bands; -} - - void wps_device_data_free(struct wps_device_data *dev) { os_free(dev->device_name); diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h index 0158cdc3..f0169a79 100644 --- a/src/wps/wps_dev_attr.h +++ b/src/wps/wps_dev_attr.h @@ -29,8 +29,6 @@ int wps_process_device_attrs(struct wps_device_data *dev, struct wps_parse_attr *attr); int wps_process_os_version(struct wps_device_data *dev, const u8 *ver); int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands); -void wps_device_data_dup(struct wps_device_data *dst, - const struct wps_device_data *src); void wps_device_data_free(struct wps_device_data *dev); int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg, diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 56949970..e729617c 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -185,10 +185,8 @@ static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap) dl_list_del(&ap->list); wps_er_ap_free(ap); - if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) { - eloop_cancel_timeout(wps_er_deinit_finish, er, NULL); + if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) wps_er_deinit_finish(er, NULL); - } } @@ -1347,9 +1345,19 @@ static void wps_er_deinit_finish(void *eloop_data, void *user_ctx) struct wps_er *er = eloop_data; void (*deinit_done_cb)(void *ctx); void *deinit_done_ctx; + struct wps_er_ap *ap, *tmp; wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit"); + dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap, + list) { + wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it", + inet_ntoa(ap->addr), ap->location); + dl_list_del(&ap->list); + wps_er_ap_free(ap); + } + + eloop_cancel_timeout(wps_er_deinit_finish, er, NULL); deinit_done_cb = er->deinit_done_cb; deinit_done_ctx = er->deinit_done_ctx; os_free(er->ip_addr_text); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index ef176170..19490a15 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -82,7 +82,7 @@ struct wps_uuid_pin { #define PIN_LOCKED BIT(0) #define PIN_EXPIRES BIT(1) int flags; - struct os_time expiration; + struct os_reltime expiration; u8 enrollee_addr[ETH_ALEN]; }; @@ -113,7 +113,7 @@ struct wps_pbc_session { struct wps_pbc_session *next; u8 addr[ETH_ALEN]; u8 uuid_e[WPS_UUID_LEN]; - struct os_time timestamp; + struct os_reltime timestamp; }; @@ -183,7 +183,9 @@ struct wps_registrar { u8 p2p_dev_addr[ETH_ALEN]; u8 pbc_ignore_uuid[WPS_UUID_LEN]; - struct os_time pbc_ignore_start; +#ifdef WPS_WORKAROUNDS + struct os_reltime pbc_ignore_start; +#endif /* WPS_WORKAROUNDS */ }; @@ -311,9 +313,9 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e) { struct wps_pbc_session *pbc, *prev = NULL; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); pbc = reg->pbc_sessions; while (pbc) { @@ -347,7 +349,8 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg, pbc = pbc->next; while (pbc) { - if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) { + if (os_reltime_expired(&now, &pbc->timestamp, + WPS_PBC_WALK_TIME)) { prev->next = NULL; wps_free_pbc_sessions(pbc); break; @@ -395,9 +398,9 @@ int wps_registrar_pbc_overlap(struct wps_registrar *reg, int count = 0; struct wps_pbc_session *pbc; struct wps_pbc_session *first = NULL; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap"); @@ -413,9 +416,9 @@ int wps_registrar_pbc_overlap(struct wps_registrar *reg, MAC2STR(pbc->addr)); wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", pbc->uuid_e, WPS_UUID_LEN); - if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) { - wpa_printf(MSG_DEBUG, "WPS: PBC walk time has " - "expired"); + if (os_reltime_expired(&now, &pbc->timestamp, + WPS_PBC_WALK_TIME)) { + wpa_printf(MSG_DEBUG, "WPS: PBC walk time has expired"); break; } if (first && @@ -748,7 +751,7 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr, if (timeout) { p->flags |= PIN_EXPIRES; - os_get_time(&p->expiration); + os_get_reltime(&p->expiration); p->expiration.sec += timeout; } @@ -797,13 +800,13 @@ static void wps_registrar_remove_pin(struct wps_registrar *reg, static void wps_registrar_expire_pins(struct wps_registrar *reg) { struct wps_uuid_pin *pin, *prev; - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) { if ((pin->flags & PIN_EXPIRES) && - os_time_before(&pin->expiration, &now)) { + os_reltime_before(&pin->expiration, &now)) { wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID", pin->uuid, WPS_UUID_LEN); wps_registrar_remove_pin(reg, pin); @@ -1037,7 +1040,9 @@ void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e, wps_registrar_remove_pbc_session(registrar, uuid_e, NULL); wps_registrar_pbc_completed(registrar); - os_get_time(®istrar->pbc_ignore_start); +#ifdef WPS_WORKAROUNDS + os_get_reltime(®istrar->pbc_ignore_start); +#endif /* WPS_WORKAROUNDS */ os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN); } else { wps_registrar_pin_completed(registrar); @@ -1140,9 +1145,9 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, #ifdef WPS_WORKAROUNDS if (reg->pbc_ignore_start.sec && os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) { - struct os_time now, dur; - os_get_time(&now); - os_time_sub(&now, ®->pbc_ignore_start, &dur); + struct os_reltime now, dur; + os_get_reltime(&now); + os_reltime_sub(&now, ®->pbc_ignore_start, &dur); if (dur.sec >= 0 && dur.sec < 5) { wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation " "based on Probe Request from the Enrollee " @@ -3189,7 +3194,9 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, wps->uuid_e, wps->p2p_dev_addr); wps_registrar_pbc_completed(wps->wps->registrar); - os_get_time(&wps->wps->registrar->pbc_ignore_start); +#ifdef WPS_WORKAROUNDS + os_get_reltime(&wps->wps->registrar->pbc_ignore_start); +#endif /* WPS_WORKAROUNDS */ os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e, WPS_UUID_LEN); } else { @@ -3446,7 +3453,7 @@ int wps_registrar_config_ap(struct wps_registrar *reg, struct wps_credential *cred) { #ifdef CONFIG_WPS2 - printf("encr_type=0x%x\n", cred->encr_type); + wpa_printf(MSG_DEBUG, "WPS: encr_type=0x%x", cred->encr_type); if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) { if (cred->encr_type & WPS_ENCR_WEP) { diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index bea2b331..6fb3d4c5 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -432,23 +432,6 @@ static void subscr_addr_list_create(struct subscription *s, } -int send_wpabuf(int fd, struct wpabuf *buf) -{ - wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message", - (unsigned long) wpabuf_len(buf)); - errno = 0; - if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) != - (int) wpabuf_len(buf)) { - wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: " - "errno=%d (%s)", - errno, strerror(errno)); - return -1; - } - - return 0; -} - - static void wpabuf_put_property(struct wpabuf *buf, const char *name, const char *value) { @@ -480,14 +463,14 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm) "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n"; const char *format_tail = "</e:propertyset>\n"; - struct os_time now; + struct os_reltime now; if (dl_list_empty(&sm->subscriptions)) { /* optimize */ return; } - if (os_get_time(&now) == 0) { + if (os_get_reltime(&now) == 0) { if (now.sec != sm->last_event_sec) { sm->last_event_sec = now.sec; sm->num_events_in_sec = 1; diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h index 5c39f7ef..f289fe68 100644 --- a/src/wps/wps_upnp_i.h +++ b/src/wps/wps_upnp_i.h @@ -158,7 +158,6 @@ void subscription_destroy(struct subscription *s); struct subscription * subscription_find(struct upnp_wps_device_sm *sm, const u8 uuid[UUID_LEN]); void subscr_addr_delete(struct subscr_addr *a); -int send_wpabuf(int fd, struct wpabuf *buf); int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, u8 mac[ETH_ALEN]); diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 260c0ae4..2c709c33 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -10,11 +10,17 @@ export LIBDIR ?= /usr/local/lib/ export BINDIR ?= /usr/local/sbin/ PKG_CONFIG ?= pkg-config -CFLAGS += -I../src -CFLAGS += -I../src/utils +CFLAGS += -I$(abspath ../src) +CFLAGS += -I$(abspath ../src/utils) -include .config +ifdef CONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_TESTING_OPTIONS +CONFIG_WPS_TESTING=y +CONFIG_TDLS_TESTING=y +endif + BINALL=wpa_supplicant wpa_cli ifndef CONFIG_NO_WPA_PASSPHRASE @@ -1622,9 +1628,15 @@ eap_eke.so: ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c $(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \ -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init +ifdef CONFIG_CODE_COVERAGE +%.o: %.c + @$(E) " CC " $< + $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<) +else %.o: %.c $(Q)$(CC) -c -o $@ $(CFLAGS) $< @$(E) " CC " $< +endif %.service: %.service.in sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ @@ -1676,6 +1688,10 @@ FIPSLD=$(FIPSDIR)/bin/fipsld fips: $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)" +lcov-html: wpa_supplicant.gcda + lcov -c -d .. > lcov.info + genhtml lcov.info --output-directory lcov-html + clean: $(MAKE) -C ../src clean $(MAKE) -C dbus clean @@ -1683,5 +1699,7 @@ clean: rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test rm -f wpa_priv rm -f nfc_pw_token + rm -f lcov.info + rm -rf lcov-html -include $(OBJS:%.o=%.d) diff --git a/wpa_supplicant/README b/wpa_supplicant/README index 8e9cc45f..7f88cd65 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -1,7 +1,7 @@ WPA Supplicant ============== -Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with @@ -983,3 +983,71 @@ directory could be created before starting the wpa_supplicant and set to suitable mode to allow wpa_supplicant to create sockets there. Alternatively, other directory or abstract socket namespace could be used for the control interface. + + +External requests for radio control +----------------------------------- + +External programs can request wpa_supplicant to not start offchannel +operations during other tasks that may need exclusive control of the +radio. The RADIO_WORK control interface command can be used for this. + +"RADIO_WORK add <name> [freq=<MHz>] [timeout=<seconds>]" command can be +used to reserve a slot for radio access. If freq is specified, other +radio work items on the same channel may be completed in +parallel. Otherwise, all other radio work items are blocked during +execution. Timeout is set to 10 seconds by default to avoid blocking +wpa_supplicant operations for excessive time. If a longer (or shorter) +safety timeout is needed, that can be specified with the optional +timeout parameter. This command returns an identifier for the radio work +item. + +Once the radio work item has been started, "EXT-RADIO-WORK-START <id>" +event message is indicated that the external processing can start. Once +the operation has been completed, "RADIO_WORK done <id>" is used to +indicate that to wpa_supplicant. This allows other radio works to be +performed. If this command is forgotten (e.g., due to the external +program terminating), wpa_supplicant will time out the radio owrk item +and send "EXT-RADIO-WORK-TIMEOUT <id>" event ot indicate that this has +happened. "RADIO_WORK done <id>" can also be used to cancel items that +have not yet been started. + +For example, in wpa_cli interactive mode: + +> radio_work add test +1 +<3>EXT-RADIO-WORK-START 1 +> radio_work show +ext:test@wlan0:0:1:2.487797 +> radio_work done 1 +OK +> radio_work show + + +> radio_work done 3 +OK +> radio_work show +ext:test freq=2412 timeout=30@wlan0:2412:1:28.583483 +<3>EXT-RADIO-WORK-TIMEOUT 2 + + +> radio_work add test2 freq=2412 timeout=60 +5 +<3>EXT-RADIO-WORK-START 5 +> radio_work add test3 +6 +> radio_work add test4 +7 +> radio_work show +ext:test2 freq=2412 timeout=60@wlan0:2412:1:9.751844 +ext:test3@wlan0:0:0:5.071812 +ext:test4@wlan0:0:0:3.143870 +> radio_work done 6 +OK +> radio_work show +ext:test2 freq=2412 timeout=60@wlan0:2412:1:16.287869 +ext:test4@wlan0:0:0:9.679895 +> radio_work done 5 +OK +<3>EXT-RADIO-WORK-START 7 +<3>EXT-RADIO-WORK-TIMEOUT 7 diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index 61e4a4dc..ad29ef77 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -109,6 +109,8 @@ Credentials can be pre-configured for automatic network selection: # # credential fields: # +# temporary: Whether this credential is temporary and not to be saved +# # priority: Priority group # By default, all networks and credentials get the same priority group # (0). This field can be used to give higher priority for credentials @@ -269,6 +271,8 @@ OK OK > set_cred 0 priority 1 OK +> set_cred 0 temporary 1 +OK Add a SIM credential using a simulated SIM/USIM card for testing: diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index ffc2baf0..08d39e24 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -418,9 +418,11 @@ p2p_presence_req [<duration> <interval>] [<duration> <interval>] Send a P2P Presence Request to the GO (this is only available when acting as a P2P client). If no duration/interval pairs are given, the request indicates that this client has no special needs for GO -presence. the first parameter pair gives the preferred duration and +presence. The first parameter pair gives the preferred duration and interval values in microseconds. If the second pair is included, that -indicates which value would be acceptable. +indicates which value would be acceptable. This command returns OK +immediately and the response from the GO is indicated in a +P2P-PRESENCE-RESPONSE event message. Parameters diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config index 501137cf..ec7df03e 100644 --- a/wpa_supplicant/android.config +++ b/wpa_supplicant/android.config @@ -20,63 +20,6 @@ # used to fix build issues on such systems (krb5.h not found). #CFLAGS += -I/usr/include/kerberos -# Example configuration for various cross-compilation platforms - -#### sveasoft (e.g., for Linksys WRT54G) ###################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS += -I../src/include -I../../src/router/openssl/include -#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl -############################################################################### - -#### openwrt (e.g., for Linksys WRT54G) ####################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \ -# -I../WRT54GS/release/src/include -#LIBS = -lssl -############################################################################### - - -# Driver interface for Host AP driver -#CONFIG_DRIVER_HOSTAP=y - -# Driver interface for Agere driver -#CONFIG_DRIVER_HERMES=y -# Change include directories to match with the local setup -#CFLAGS += -I../../hcf -I../../include -I../../include/hcf -#CFLAGS += -I../../include/wireless - -# Driver interface for madwifi driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_MADWIFI=y -# Set include directory to the madwifi source tree -#CFLAGS += -I../../madwifi - -# Driver interface for ndiswrapper -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_NDISWRAPPER=y - -# Driver interface for Atmel driver -#CONFIG_DRIVER_ATMEL=y - -# Driver interface for old Broadcom driver -# Please note that the newer Broadcom driver ("hybrid Linux driver") supports -# Linux wireless extensions and does not need (or even work) with the old -# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver. -#CONFIG_DRIVER_BROADCOM=y -# Example path for wlioctl.h; change to match your configuration -#CFLAGS += -I/opt/WRT54GS/release/src/include - -# Driver interface for Intel ipw2100/2200 driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_IPW=y - -# Driver interface for Ralink driver -#CONFIG_DRIVER_RALINK=y - # Driver interface for generic Linux wireless extensions # Note: WEXT is deprecated in the current Linux kernel version and no new # functionality is added to it. nl80211-based interface is the new diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 394ab30d..ea4e6bba 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -276,7 +276,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) && (bss->wpa_group == WPA_CIPHER_CCMP || - bss->wpa_group == WPA_CIPHER_GCMP)) { + bss->wpa_group == WPA_CIPHER_GCMP || + bss->wpa_group == WPA_CIPHER_CCMP_256 || + bss->wpa_group == WPA_CIPHER_GCMP_256)) { /* * Strong ciphers do not need frequent rekeying, so increase * the default GTK rekeying period to 24 hours. @@ -511,7 +513,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; else wpa_s->key_mgmt = WPA_KEY_MGMT_NONE; - params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt); + params.key_mgmt_suite = wpa_s->key_mgmt; wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 1); @@ -520,8 +522,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, "cipher."); return -1; } - params.pairwise_suite = - wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher); + params.pairwise_suite = wpa_s->pairwise_cipher; params.group_suite = params.pairwise_suite; #ifdef CONFIG_P2P @@ -679,6 +680,8 @@ void ap_eapol_tx_status(void *ctx, const u8 *dst, { #ifdef NEED_AP_MLME struct wpa_supplicant *wpa_s = ctx; + if (!wpa_s->ap_iface) + return; hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack); #endif /* NEED_AP_MLME */ } diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c index 07d31e4c..6a92b735 100644 --- a/wpa_supplicant/bgscan_learn.c +++ b/wpa_supplicant/bgscan_learn.c @@ -34,7 +34,7 @@ struct bgscan_learn_data { int signal_threshold; int short_interval; /* use if signal < threshold */ int long_interval; /* use if signal > threshold */ - struct os_time last_bgscan; + struct os_reltime last_bgscan; char *fname; struct dl_list bss; int *supp_freqs; @@ -240,17 +240,14 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data, if (data->supp_freqs == NULL) return freqs; - idx = data->probe_idx + 1; - while (idx != data->probe_idx) { - if (data->supp_freqs[idx] == 0) { - if (data->probe_idx == 0) - break; - idx = 0; - } + idx = data->probe_idx; + do { if (!in_array(freqs, data->supp_freqs[idx])) { wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq " "%u", data->supp_freqs[idx]); - data->probe_idx = idx; + data->probe_idx = idx + 1; + if (data->supp_freqs[data->probe_idx] == 0) + data->probe_idx = 0; n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) return freqs; @@ -262,7 +259,9 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data, } idx++; - } + if (data->supp_freqs[idx] == 0) + idx = 0; + } while (idx != data->probe_idx); return freqs; } @@ -311,7 +310,7 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx) eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); } else - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); os_free(freqs); } @@ -363,6 +362,9 @@ static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s) for (j = 0; j < modes[i].num_channels; j++) { if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED) continue; + /* some hw modes (e.g. 11b & 11g) contain same freqs */ + if (in_array(freqs, modes[i].channels[j].freq)) + continue; n = os_realloc_array(freqs, count + 2, sizeof(int)); if (n == NULL) continue; @@ -419,6 +421,14 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s, data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s); data->scan_interval = data->short_interval; + if (data->signal_threshold) { + /* Poll for signal info to set initial scan interval */ + struct wpa_signal_info siginfo; + if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 && + siginfo.current_signal >= data->signal_threshold) + data->scan_interval = data->long_interval; + } + eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); @@ -428,7 +438,7 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s, * us skip an immediate new scan in cases where the current signal * level is below the bgscan threshold. */ - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); return data; } @@ -555,7 +565,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above, { struct bgscan_learn_data *data = priv; int scan = 0; - struct os_time now; + struct os_reltime now; if (data->short_interval == data->long_interval || data->signal_threshold == 0) @@ -569,7 +579,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above, wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan " "interval"); data->scan_interval = data->short_interval; - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 1) scan = 1; } else if (data->scan_interval == data->short_interval && above) { @@ -584,7 +594,7 @@ static void bgscan_learn_notify_signal_change(void *priv, int above, * Signal dropped further 4 dB. Request a new scan if we have * not yet scanned in a while. */ - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 10) scan = 1; } diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c index 479f703b..a467cc5b 100644 --- a/wpa_supplicant/bgscan_simple.c +++ b/wpa_supplicant/bgscan_simple.c @@ -26,7 +26,7 @@ struct bgscan_simple_data { int max_short_scans; /* maximum times we short-scan before back-off */ int short_interval; /* use if signal < threshold */ int long_interval; /* use if signal > threshold */ - struct os_time last_bgscan; + struct os_reltime last_bgscan; }; @@ -75,7 +75,7 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx) */ data->short_scan_count--; } - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); } } @@ -159,7 +159,7 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s, * us skip an immediate new scan in cases where the current signal * level is below the bgscan threshold. */ - os_get_time(&data->last_bgscan); + os_get_reltime(&data->last_bgscan); return data; } @@ -211,7 +211,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above, { struct bgscan_simple_data *data = priv; int scan = 0; - struct os_time now; + struct os_reltime now; if (data->short_interval == data->long_interval || data->signal_threshold == 0) @@ -225,7 +225,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above, wpa_printf(MSG_DEBUG, "bgscan simple: Start using short " "bgscan interval"); data->scan_interval = data->short_interval; - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 1 && data->short_scan_count <= data->max_short_scans) /* @@ -259,7 +259,7 @@ static void bgscan_simple_notify_signal_change(void *priv, int above, * Signal dropped further 4 dB. Request a new scan if we have * not yet scanned in a while. */ - os_get_time(&now); + os_get_reltime(&now); if (now.sec > data->last_bgscan.sec + 10) scan = 1; } diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index df1a0c88..9ea69033 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -224,9 +224,9 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, } -static void calculate_update_time(const struct os_time *fetch_time, +static void calculate_update_time(const struct os_reltime *fetch_time, unsigned int age_ms, - struct os_time *update_time) + struct os_reltime *update_time) { os_time_t usec; @@ -243,7 +243,7 @@ static void calculate_update_time(const struct os_time *fetch_time, static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, - struct os_time *fetch_time) + struct os_reltime *fetch_time) { dst->flags = src->flags; os_memcpy(dst->bssid, src->bssid, ETH_ALEN); @@ -326,7 +326,7 @@ static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len, struct wpa_scan_res *res, - struct os_time *fetch_time) + struct os_reltime *fetch_time) { struct wpa_bss *bss; @@ -492,7 +492,7 @@ static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes, static struct wpa_bss * wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - struct wpa_scan_res *res, struct os_time *fetch_time) + struct wpa_scan_res *res, struct os_reltime *fetch_time) { u32 changes; @@ -587,17 +587,18 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s) */ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, - struct os_time *fetch_time) + struct os_reltime *fetch_time) { const u8 *ssid, *p2p; struct wpa_bss *bss; if (wpa_s->conf->ignore_old_scan_res) { - struct os_time update; + struct os_reltime update; calculate_update_time(fetch_time, res->age, &update); - if (os_time_before(&update, &wpa_s->scan_trigger_time)) { - struct os_time age; - os_time_sub(&wpa_s->scan_trigger_time, &update, &age); + if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) { + struct os_reltime age; + os_reltime_sub(&wpa_s->scan_trigger_time, &update, + &age); wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS " "table entry that is %u.%06u seconds older " "than our scan trigger", @@ -731,26 +732,10 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, { struct wpa_bss *bss, *n; - wpa_s->last_scan_full = 0; - os_get_time(&wpa_s->last_scan); + os_get_reltime(&wpa_s->last_scan); if (!new_scan) return; /* do not expire entries without new scan */ - if (info && !info->aborted && !info->freqs) { - size_t i; - if (info->num_ssids == 0) { - wpa_s->last_scan_full = 1; - } else { - for (i = 0; i < info->num_ssids; i++) { - if (info->ssids[i].ssid == NULL || - info->ssids[i].ssid_len == 0) { - wpa_s->last_scan_full = 1; - break; - } - } - } - } - dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; @@ -764,10 +749,8 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, } } - wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u " - "last_scan_full=%d", - wpa_s->last_scan_res_used, wpa_s->last_scan_res_size, - wpa_s->last_scan_full); + wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u", + wpa_s->last_scan_res_used, wpa_s->last_scan_res_size); } @@ -781,19 +764,19 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) { struct wpa_bss *bss, *n; - struct os_time t; + struct os_reltime t; if (dl_list_empty(&wpa_s->bss)) return; - os_get_time(&t); + os_get_reltime(&t); t.sec -= age; dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; - if (os_time_before(&bss->last_update, &t)) { + if (os_reltime_before(&bss->last_update, &t)) { wpa_bss_remove(wpa_s, bss, __func__); } else break; @@ -837,6 +820,8 @@ void wpa_bss_flush(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss, *n; + wpa_s->clear_driver_scan_cache = 1; + if (wpa_s->bss.next == NULL) return; /* BSS table not yet initialized */ @@ -900,7 +885,7 @@ struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s, if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0) continue; if (found == NULL || - os_time_before(&found->last_update, &bss->last_update)) + os_reltime_before(&found->last_update, &bss->last_update)) found = bss; } return found; diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 0d2693fd..4deeb5f5 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -84,7 +84,7 @@ struct wpa_bss { /** Timestamp of last Beacon/Probe Response frame */ u64 tsf; /** Time of the last update (i.e., Beacon or Probe Response RX) */ - struct os_time last_update; + struct os_reltime last_update; /** ANQP data */ struct wpa_bss_anqp *anqp; /** Length of the following IE field in octets (from Probe Response) */ @@ -98,7 +98,7 @@ struct wpa_bss { void wpa_bss_update_start(struct wpa_supplicant *wpa_s); void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, - struct os_time *fetch_time); + struct os_reltime *fetch_time); void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, int new_scan); int wpa_bss_init(struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 9ceaaf85..5301ed71 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2393,6 +2393,11 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, char *val; size_t len; + if (os_strcmp(var, "temporary") == 0) { + cred->temporary = atoi(value); + return 0; + } + if (os_strcmp(var, "priority") == 0) { cred->priority = atoi(value); return 0; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 068679e5..e24772d1 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -52,6 +52,11 @@ struct wpa_cred { int id; /** + * temporary - Whether this credential is temporary and not to be saved + */ + int temporary; + + /** * priority - Priority group * * By default, all networks and credentials get the same priority group diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 7d328673..6312a77b 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1110,6 +1110,8 @@ int wpa_config_write(const char *name, struct wpa_config *config) wpa_config_write_global(f, config); for (cred = config->cred; cred; cred = cred->next) { + if (cred->temporary) + continue; fprintf(f, "\ncred={\n"); wpa_config_write_cred(f, cred); fprintf(f, "}\n"); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 0102da94..d515030f 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -315,12 +315,13 @@ struct wpa_ssid { * 4 = P2P Group Formation (used internally; not in configuration * files) * - * Note: IBSS can only be used with key_mgmt NONE (plaintext and - * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In - * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires - * following network block options: proto=WPA, key_mgmt=WPA-NONE, - * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also - * be set (either directly or using ASCII passphrase). + * Note: IBSS can only be used with key_mgmt NONE (plaintext and static + * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE + * (fixed group key TKIP/CCMP) is available for backwards compatibility, + * but its use is deprecated. WPA-None requires following network block + * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or + * CCMP, but not both), and psk must also be set (either directly or + * using ASCII passphrase). */ enum wpas_mode { WPAS_MODE_INFRA = 0, @@ -610,7 +611,7 @@ struct wpa_ssid { /** * disabled_until - Network block disabled until this time if non-zero */ - struct os_time disabled_until; + struct os_reltime disabled_until; /** * parent_cred - Pointer to parent wpa_cred entry diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 4e344b8c..cb299db0 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Control interface (shared code for all backends) - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -10,6 +10,7 @@ #include "utils/common.h" #include "utils/eloop.h" +#include "utils/uuid.h" #include "common/version.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" @@ -40,8 +41,6 @@ #include "autoscan.h" #include "wnm_sta.h" -extern struct wpa_driver_ops *wpa_drivers[]; - static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, @@ -361,13 +360,13 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "ampdu") == 0) { if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) ret = -1; +#ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING } else if (os_strcasecmp(cmd, "tdls_testing") == 0) { extern unsigned int tdls_testing; tdls_testing = strtol(value, NULL, 0); wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing); #endif /* CONFIG_TDLS_TESTING */ -#ifdef CONFIG_TDLS } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) { int disabled = atoi(value); wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled); @@ -1629,6 +1628,17 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, if (res >= 0) pos += res; +#ifdef CONFIG_WPS + { + char uuid_str[100]; + uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str)); + ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_WPS */ + #ifdef ANDROID wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE "id=%d state=%d BSSID=" MACSTR " SSID=%s", @@ -1740,9 +1750,6 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s, } -extern int wpa_debug_level; -extern int wpa_debug_timestamp; - static const char * debug_level_str(int level) { switch (level) { @@ -2658,6 +2665,24 @@ static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) #endif /* CONFIG_NO_CONFIG_WRITE */ +struct cipher_info { + unsigned int capa; + const char *name; + int group_only; +}; + +static const struct cipher_info ciphers[] = { + { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 }, + { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 }, + { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 }, + { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 }, + { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 }, + { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 }, + { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 }, + { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 } +}; + + static int ctrl_iface_get_capability_pairwise(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) @@ -2665,6 +2690,7 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict, int ret, first = 1; char *pos, *end; size_t len; + unsigned int i; pos = buf; end = pos + buflen; @@ -2678,36 +2704,15 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict, return len; } - if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) { - ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) { - ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { - ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { - ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; + for (i = 0; i < ARRAY_SIZE(ciphers); i++) { + if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) { + ret = os_snprintf(pos, end - pos, "%s%s", + first ? "" : " ", ciphers[i].name); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } } return pos - buf; @@ -2721,6 +2726,7 @@ static int ctrl_iface_get_capability_group(int res, char *strict, int ret, first = 1; char *pos, *end; size_t len; + unsigned int i; pos = buf; end = pos + buflen; @@ -2734,45 +2740,15 @@ static int ctrl_iface_get_capability_group(int res, char *strict, return len; } - if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) { - ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) { - ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { - ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) { - ret = os_snprintf(pos, end - pos, "%sWEP104", - first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; - } - - if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) { - ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " "); - if (ret < 0 || ret >= end - pos) - return pos - buf; - pos += ret; - first = 0; + for (i = 0; i < ARRAY_SIZE(ciphers); i++) { + if (capa->enc & ciphers[i].capa) { + ret = os_snprintf(pos, end - pos, "%s%s", + first ? "" : " ", ciphers[i].name); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } } return pos - buf; @@ -3248,9 +3224,9 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } if (mask & WPA_BSS_MASK_AGE) { - struct os_time now; + struct os_reltime now; - os_get_time(&now); + os_get_reltime(&now); ret = os_snprintf(pos, end - pos, "age=%d\n", (int) (now.sec - bss->last_update.sec)); if (ret < 0 || ret >= end - pos) @@ -4688,7 +4664,68 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd) #endif /* CONFIG_P2P */ +static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val) +{ + struct wpa_freq_range_list ranges; + int *freqs = NULL; + struct hostapd_hw_modes *mode; + u16 i; + + if (wpa_s->hw.modes == NULL) + return NULL; + + os_memset(&ranges, 0, sizeof(ranges)); + if (freq_range_list_parse(&ranges, val) < 0) + return NULL; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + int j; + + mode = &wpa_s->hw.modes[i]; + for (j = 0; j < mode->num_channels; j++) { + unsigned int freq; + + if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED) + continue; + + freq = mode->channels[j].freq; + if (!freq_range_list_includes(&ranges, freq)) + continue; + + int_array_add_unique(&freqs, freq); + } + } + + os_free(ranges.range); + return freqs; +} + + #ifdef CONFIG_INTERWORKING + +static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param) +{ + int auto_sel = 0; + int *freqs = NULL; + + if (param) { + char *pos; + + auto_sel = os_strstr(param, "auto") != NULL; + + pos = os_strstr(param, "freq="); + if (pos) { + freqs = freq_range_to_channel_list(wpa_s, pos + 5); + if (freqs == NULL) + return -1; + } + + } + + return interworking_select(wpa_s, auto_sel, freqs); +} + + static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst) { u8 bssid[ETH_ALEN]; @@ -4812,9 +4849,8 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, int used; char *pos; size_t resp_len, start, requested_len; - - if (!wpa_s->last_gas_resp) - return -1; + struct wpabuf *resp; + int ret; used = hwaddr_aton2(cmd, addr); if (used < 0) @@ -4825,11 +4861,18 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, pos++; dialog_token = atoi(pos); - if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 || - dialog_token != wpa_s->last_gas_dialog_token) + if (wpa_s->last_gas_resp && + os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 && + dialog_token == wpa_s->last_gas_dialog_token) + resp = wpa_s->last_gas_resp; + else if (wpa_s->prev_gas_resp && + os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 && + dialog_token == wpa_s->prev_gas_dialog_token) + resp = wpa_s->prev_gas_resp; + else return -1; - resp_len = wpabuf_len(wpa_s->last_gas_resp); + resp_len = wpabuf_len(resp); start = 0; requested_len = resp_len; @@ -4850,9 +4893,24 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, if (requested_len * 2 + 1 > buflen) return os_snprintf(buf, buflen, "FAIL-Too long response"); - return wpa_snprintf_hex(buf, buflen, - wpabuf_head_u8(wpa_s->last_gas_resp) + start, - requested_len); + ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start, + requested_len); + + if (start + requested_len == resp_len) { + /* + * Free memory by dropping the response after it has been + * fetched. + */ + if (resp == wpa_s->prev_gas_resp) { + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = NULL; + } else { + wpabuf_free(wpa_s->last_gas_resp); + wpa_s->last_gas_resp = NULL; + } + } + + return ret; } #endif /* CONFIG_INTERWORKING */ @@ -5191,6 +5249,9 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpas_p2p_stop_find(wpa_s); p2p_ctrl_flush(wpa_s); wpas_p2p_group_remove(wpa_s, "*"); + wpas_p2p_service_flush(wpa_s); + wpa_s->global->p2p_disabled = 0; + wpa_s->global->p2p_per_sta_psk = 0; #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS_TESTING @@ -5198,16 +5259,17 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wps_testing_dummy_cred = 0; #endif /* CONFIG_WPS_TESTING */ #ifdef CONFIG_WPS + wpa_s->wps_fragment_size = 0; wpas_wps_cancel(wpa_s); #endif /* CONFIG_WPS */ wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; +#ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING extern unsigned int tdls_testing; tdls_testing = 0; #endif /* CONFIG_TDLS_TESTING */ -#ifdef CONFIG_TDLS wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL); wpa_tdls_enable(wpa_s->wpa, 1); #endif /* CONFIG_TDLS */ @@ -5234,6 +5296,193 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->extra_blacklist_count = 0; wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all"); wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all"); + + wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200); + wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70); + wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60); + eapol_sm_notify_logoff(wpa_s->eapol, FALSE); + + radio_remove_unstarted_work(wpa_s, NULL); +} + + +static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + struct wpa_radio_work *work; + char *pos, *end; + struct os_reltime now, diff; + + pos = buf; + end = buf + buflen; + + os_get_reltime(&now); + + dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) + { + int ret; + + os_reltime_sub(&now, &work->time, &diff); + ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n", + work->type, work->wpa_s->ifname, work->freq, + work->started, diff.sec, diff.usec); + if (ret < 0 || ret >= end - pos) + break; + pos += ret; + } + + return pos - buf; +} + + +static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_radio_work *work = eloop_ctx; + struct wpa_external_work *ework = work->ctx; + + wpa_dbg(work->wpa_s, MSG_DEBUG, + "Timing out external radio work %u (%s)", + ework->id, work->type); + wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id); + os_free(ework); + radio_work_done(work); +} + + +static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_external_work *ework = work->ctx; + + if (deinit) { + os_free(ework); + return; + } + + wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)", + ework->id, ework->type); + wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id); + if (!ework->timeout) + ework->timeout = 10; + eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout, + work, NULL); +} + + +static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + struct wpa_external_work *ework; + char *pos, *pos2; + size_t type_len; + int ret; + unsigned int freq = 0; + + /* format: <name> [freq=<MHz>] [timeout=<seconds>] */ + + ework = os_zalloc(sizeof(*ework)); + if (ework == NULL) + return -1; + + pos = os_strchr(cmd, ' '); + if (pos) { + type_len = pos - cmd; + pos++; + + pos2 = os_strstr(pos, "freq="); + if (pos2) + freq = atoi(pos2 + 5); + + pos2 = os_strstr(pos, "timeout="); + if (pos2) + ework->timeout = atoi(pos2 + 8); + } else { + type_len = os_strlen(cmd); + } + if (4 + type_len >= sizeof(ework->type)) + type_len = sizeof(ework->type) - 4 - 1; + os_strlcpy(ework->type, "ext:", sizeof(ework->type)); + os_memcpy(ework->type + 4, cmd, type_len); + ework->type[4 + type_len] = '\0'; + + wpa_s->ext_work_id++; + if (wpa_s->ext_work_id == 0) + wpa_s->ext_work_id++; + ework->id = wpa_s->ext_work_id; + + if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb, + ework) < 0) { + os_free(ework); + return -1; + } + + ret = os_snprintf(buf, buflen, "%u", ework->id); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; +} + + +static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd) +{ + struct wpa_radio_work *work; + unsigned int id = atoi(cmd); + + dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list) + { + struct wpa_external_work *ework; + + if (os_strncmp(work->type, "ext:", 4) != 0) + continue; + ework = work->ctx; + if (id && ework->id != id) + continue; + wpa_dbg(wpa_s, MSG_DEBUG, + "Completed external radio work %u (%s)", + ework->id, ework->type); + eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); + os_free(ework); + radio_work_done(work); + return 3; /* "OK\n" */ + } + + return -1; +} + + +static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + if (os_strcmp(cmd, "show") == 0) + return wpas_ctrl_radio_work_show(wpa_s, buf, buflen); + if (os_strncmp(cmd, "add ", 4) == 0) + return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen); + if (os_strncmp(cmd, "done ", 5) == 0) + return wpas_ctrl_radio_work_done(wpa_s, cmd + 4); + return -1; +} + + +void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) +{ + struct wpa_radio_work *work, *tmp; + + dl_list_for_each_safe(work, tmp, &wpa_s->radio->work, + struct wpa_radio_work, list) { + struct wpa_external_work *ework; + + if (os_strncmp(work->type, "ext:", 4) != 0) + continue; + ework = work->ctx; + wpa_dbg(wpa_s, MSG_DEBUG, + "Flushing %sexternal radio work %u (%s)", + work->started ? " started" : "", ework->id, + ework->type); + if (work->started) + eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, + work, NULL); + os_free(ework); + radio_work_done(work); + } } @@ -5244,6 +5493,97 @@ static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx) } +static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val) +{ + int *freqs = NULL; + + freqs = freq_range_to_channel_list(wpa_s, val); + if (freqs == NULL) + return -1; + + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; + + return 0; +} + + +static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, + char *reply, int reply_size, int *reply_len) +{ + char *pos; + + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + *reply_len = -1; + return; + } + + wpa_s->manual_scan_passive = 0; + wpa_s->manual_scan_use_id = 0; + wpa_s->manual_scan_only_new = 0; + + if (params) { + if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0) + wpa_s->scan_res_handler = scan_only_handler; + + pos = os_strstr(params, "freq="); + if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) { + *reply_len = -1; + return; + } + + pos = os_strstr(params, "passive="); + if (pos) + wpa_s->manual_scan_passive = !!atoi(pos + 8); + + pos = os_strstr(params, "use_id="); + if (pos) + wpa_s->manual_scan_use_id = atoi(pos + 7); + + pos = os_strstr(params, "only_new=1"); + if (pos) + wpa_s->manual_scan_only_new = 1; + } else { + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + if (wpa_s->scan_res_handler == scan_only_handler) + wpa_s->scan_res_handler = NULL; + } + + if (!wpa_s->sched_scanning && !wpa_s->scanning && + ((wpa_s->wpa_state <= WPA_SCANNING) || + (wpa_s->wpa_state == WPA_COMPLETED))) { + wpa_s->normal_scans = 0; + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->after_wps = 0; + wpa_s->known_wps_freq = 0; + wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_s->manual_scan_use_id) { + wpa_s->manual_scan_id++; + wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", + wpa_s->manual_scan_id); + *reply_len = os_snprintf(reply, reply_size, "%u\n", + wpa_s->manual_scan_id); + } + } else if (wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed"); + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_supplicant_req_scan(wpa_s, 0, 0); + if (wpa_s->manual_scan_use_id) { + wpa_s->manual_scan_id++; + *reply_len = os_snprintf(reply, reply_size, "%u\n", + wpa_s->manual_scan_id); + wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u", + wpa_s->manual_scan_id); + } + } else { + wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request"); + *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); + } +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -5252,18 +5592,25 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, int reply_len; if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || - os_strncmp(buf, "SET_NETWORK ", 12) == 0 || - os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || - os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 || - os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) { + os_strncmp(buf, "SET_NETWORK ", 12) == 0) { + if (wpa_debug_show_keys) + wpa_dbg(wpa_s, MSG_DEBUG, + "Control interface command '%s'", buf); + else + wpa_dbg(wpa_s, MSG_DEBUG, + "Control interface command '%s [REMOVED]'", + os_strncmp(buf, WPA_CTRL_RSP, + os_strlen(WPA_CTRL_RSP)) == 0 ? + WPA_CTRL_RSP : "SET_NETWORK"); + } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 || + os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 || + os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) { wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", (const u8 *) buf, os_strlen(buf)); } else { int level = MSG_DEBUG; if (os_strcmp(buf, "PING") == 0) level = MSG_EXCESSIVE; - wpa_hexdump_ascii(level, "RX ctrl_iface", - (const u8 *) buf, os_strlen(buf)); wpa_dbg(wpa_s, level, "Control interface command '%s'", buf); } @@ -5557,9 +5904,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) { interworking_stop_fetch_anqp(wpa_s); - } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) { - if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") != - NULL) < 0) + } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) { + if (ctrl_interworking_select(wpa_s, NULL) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) { + if (ctrl_interworking_select(wpa_s, buf + 20) < 0) reply_len = -1; } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) { if (ctrl_interworking_connect(wpa_s, buf + 21) < 0) @@ -5622,36 +5971,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); - } else if (os_strcmp(buf, "SCAN") == 0 || - os_strncmp(buf, "SCAN ", 5) == 0) { - if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) - reply_len = -1; - else { - if (os_strlen(buf) > 4 && - os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0) - wpa_s->scan_res_handler = scan_only_handler; - if (!wpa_s->sched_scanning && !wpa_s->scanning && - ((wpa_s->wpa_state <= WPA_SCANNING) || - (wpa_s->wpa_state == WPA_COMPLETED))) { - wpa_s->normal_scans = 0; - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_s->after_wps = 0; - wpa_s->known_wps_freq = 0; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else if (wpa_s->sched_scanning) { - wpa_printf(MSG_DEBUG, "Stop ongoing " - "sched_scan to allow requested " - "full scan to proceed"); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else { - wpa_printf(MSG_DEBUG, "Ongoing scan action - " - "reject new request"); - reply_len = os_snprintf(reply, reply_size, - "FAIL-BUSY\n"); - } - } + } else if (os_strcmp(buf, "SCAN") == 0) { + wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); + } else if (os_strncmp(buf, "SCAN ", 5) == 0) { + wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len); } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); @@ -5792,6 +6115,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WNM */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); + } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { + reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply, + reply_size); } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h index a329ef32..b0dec53f 100644 --- a/wpa_supplicant/ctrl_iface.h +++ b/wpa_supplicant/ctrl_iface.h @@ -113,6 +113,8 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global); void wpa_supplicant_global_ctrl_iface_deinit( struct ctrl_iface_global_priv *priv); +void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s); + #else /* CONFIG_CTRL_IFACE */ static inline struct ctrl_iface_priv * @@ -148,6 +150,10 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) { } +static inline void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) +{ +} + #endif /* CONFIG_CTRL_IFACE */ #endif /* CTRL_IFACE_H */ diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index 7135d068..8fb217da 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / UNIX domain socket -based control interface - * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -75,6 +75,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, socklen_t fromlen) { struct wpa_ctrl_dst *dst; + char addr_txt[200]; dst = os_zalloc(sizeof(*dst)); if (dst == NULL) @@ -83,9 +84,10 @@ static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, dst->addrlen = fromlen; dst->debug_level = MSG_INFO; dl_list_add(ctrl_dst, &dst->list); - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) from->sun_path, + fromlen - offsetof(struct sockaddr_un, sun_path)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s", addr_txt); return 0; } @@ -101,10 +103,13 @@ static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, os_memcmp(from->sun_path, dst->addr.sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)) == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); + char addr_txt[200]; + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) from->sun_path, + fromlen - + offsetof(struct sockaddr_un, sun_path)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s", + addr_txt); dl_list_del(&dst->list); os_free(dst); return 0; @@ -128,11 +133,13 @@ static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, os_memcmp(from->sun_path, dst->addr.sun_path, fromlen - offsetof(struct sockaddr_un, sun_path)) == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); + char addr_txt[200]; dst->debug_level = atoi(level); + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) from->sun_path, fromlen - + offsetof(struct sockaddr_un, sun_path)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", + dst->debug_level, addr_txt); return 0; } } @@ -676,32 +683,33 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, msg.msg_iov = io; msg.msg_iovlen = idx; - idx = -1; dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { int _errno; + char addr_txt[200]; - idx++; if (level < dst->debug_level) continue; - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) dst->addr.sun_path, dst->addrlen - + offsetof(struct sockaddr_un, sun_path)); msg.msg_name = (void *) &dst->addr; msg.msg_namelen = dst->addrlen; if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor sent successfully to %s", + addr_txt); dst->errors = 0; - idx++; continue; } _errno = errno; - wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: %d - %s", - idx, errno, strerror(errno)); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", + addr_txt, errno, strerror(errno)); dst->errors++; if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { - wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages"); + wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", + addr_txt); wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, dst->addrlen); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index fdf9a0a6..5380b430 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -28,10 +28,6 @@ #include "dbus_dict_helpers.h" #include "dbus_common_i.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - static const char *debug_strings[] = { "excessive", "msgdump", "debug", "info", "warning", "error", NULL }; @@ -2260,6 +2256,18 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, &iter_array)) goto nomem; + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp-256")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp-256")) + goto nomem; + } + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp")) @@ -2307,6 +2315,18 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, &iter_array)) goto nomem; + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "ccmp-256")) + goto nomem; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "gcmp-256")) + goto nomem; + } + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { if (!wpa_dbus_dict_string_array_add_element( &iter_array, "ccmp")) @@ -3601,7 +3621,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, { DBusMessageIter iter_dict, variant_iter; const char *group; - const char *pairwise[3]; /* max 3 pairwise ciphers is supported */ + const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ const char *key_mgmt[7]; /* max 7 key managements may be supported */ int n; @@ -3650,6 +3670,12 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, case WPA_CIPHER_WEP104: group = "wep104"; break; + case WPA_CIPHER_CCMP_256: + group = "ccmp-256"; + break; + case WPA_CIPHER_GCMP_256: + group = "gcmp-256"; + break; default: group = ""; break; @@ -3666,6 +3692,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, pairwise[n++] = "ccmp"; if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP) pairwise[n++] = "gcmp"; + if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256) + pairwise[n++] = "ccmp-256"; + if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256) + pairwise[n++] = "gcmp-256"; if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", pairwise, n)) diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c index 6d178f45..7c4630e4 100644 --- a/wpa_supplicant/dbus/dbus_old_handlers.c +++ b/wpa_supplicant/dbus/dbus_old_handlers.c @@ -25,10 +25,6 @@ #include "dbus_old_handlers.h" #include "dbus_dict_helpers.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; - /** * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message * @message: Pointer to incoming dbus message this error refers to diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index ea0db04f..0627661c 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -20,63 +20,6 @@ # used to fix build issues on such systems (krb5.h not found). #CFLAGS += -I/usr/include/kerberos -# Example configuration for various cross-compilation platforms - -#### sveasoft (e.g., for Linksys WRT54G) ###################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS += -I../src/include -I../../src/router/openssl/include -#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl -############################################################################### - -#### openwrt (e.g., for Linksys WRT54G) ####################################### -#CC=mipsel-uclibc-gcc -#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc -#CFLAGS += -Os -#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \ -# -I../WRT54GS/release/src/include -#LIBS = -lssl -############################################################################### - - -# Driver interface for Host AP driver -CONFIG_DRIVER_HOSTAP=y - -# Driver interface for Agere driver -#CONFIG_DRIVER_HERMES=y -# Change include directories to match with the local setup -#CFLAGS += -I../../hcf -I../../include -I../../include/hcf -#CFLAGS += -I../../include/wireless - -# Driver interface for madwifi driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_MADWIFI=y -# Set include directory to the madwifi source tree -#CFLAGS += -I../../madwifi - -# Driver interface for ndiswrapper -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_NDISWRAPPER=y - -# Driver interface for Atmel driver -CONFIG_DRIVER_ATMEL=y - -# Driver interface for old Broadcom driver -# Please note that the newer Broadcom driver ("hybrid Linux driver") supports -# Linux wireless extensions and does not need (or even work) with the old -# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver. -#CONFIG_DRIVER_BROADCOM=y -# Example path for wlioctl.h; change to match your configuration -#CFLAGS += -I/opt/WRT54GS/release/src/include - -# Driver interface for Intel ipw2100/2200 driver -# Deprecated; use CONFIG_DRIVER_WEXT=y instead. -#CONFIG_DRIVER_IPW=y - -# Driver interface for Ralink driver -#CONFIG_DRIVER_RALINK=y - # Driver interface for generic Linux wireless extensions # Note: WEXT is deprecated in the current Linux kernel version and no new # functionality is added to it. nl80211-based interface is the new @@ -147,10 +90,9 @@ CONFIG_EAP_PEAP=y CONFIG_EAP_TTLS=y # EAP-FAST -# Note: Default OpenSSL package does not include support for all the -# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, -# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch) -# to add the needed functions. +# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed +# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g., +# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions. #CONFIG_EAP_FAST=y # EAP-GTC diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 7f196de2..0691b6ca 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -117,11 +117,16 @@ static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid) static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + if (alg != WPA_ALG_NONE) { + if (key_idx >= 0 && key_idx <= 6) + wpa_s->keys_cleared &= ~BIT(key_idx); + else + wpa_s->keys_cleared = 0; + } if (wpa_s->driver->set_key) { - wpa_s->keys_cleared = 0; return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); @@ -516,134 +521,6 @@ static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu) return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu); } -static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s, - unsigned int timeout, int type) -{ - if (!wpa_s->driver->p2p_find) - return -1; - return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type); -} - -static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->driver->p2p_stop_find) - return -1; - return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv); -} - -static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s, - unsigned int timeout) -{ - if (!wpa_s->driver->p2p_listen) - return -1; - return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout); -} - -static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s, - const u8 *peer_addr, int wps_method, - int go_intent, - const u8 *own_interface_addr, - unsigned int force_freq, - int persistent_group) -{ - if (!wpa_s->driver->p2p_connect) - return -1; - return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr, - wps_method, go_intent, - own_interface_addr, force_freq, - persistent_group); -} - -static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s, - const u8 *peer_addr) -{ - if (!wpa_s->driver->wps_success_cb) - return -1; - return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr); -} - -static inline int -wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->driver->p2p_group_formation_failed) - return -1; - return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv); -} - -static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s, - const struct p2p_params *params) -{ - if (!wpa_s->driver->p2p_set_params) - return -1; - return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params); -} - -static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s, - const u8 *peer_addr, - u16 config_methods, int join) -{ - if (!wpa_s->driver->p2p_prov_disc_req) - return -1; - return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr, - config_methods, join); -} - -static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s, - const u8 *dst, - const struct wpabuf *tlvs) -{ - if (!wpa_s->driver->p2p_sd_request) - return 0; - return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs); -} - -static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, - u64 req) -{ - if (!wpa_s->driver->p2p_sd_cancel_request) - return -1; - return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req); -} - -static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s, - int freq, const u8 *dst, - u8 dialog_token, - const struct wpabuf *resp_tlvs) -{ - if (!wpa_s->driver->p2p_sd_response) - return -1; - return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst, - dialog_token, resp_tlvs); -} - -static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->driver->p2p_service_update) - return -1; - return wpa_s->driver->p2p_service_update(wpa_s->drv_priv); -} - -static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s, - const u8 *addr) -{ - if (!wpa_s->driver->p2p_reject) - return -1; - return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr); -} - -static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s, - const u8 *peer, int role, const u8 *bssid, - const u8 *ssid, size_t ssid_len, - const u8 *go_dev_addr, - int persistent_group) -{ - if (!wpa_s->driver->p2p_invite) - return -1; - return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid, - ssid, ssid_len, go_dev_addr, - persistent_group); -} - static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index 2b25b699..cb714754 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -30,9 +30,6 @@ #include "wpas_glue.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; - struct wpa_driver_ops *wpa_drivers[] = { NULL }; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index c03dcc25..49c4058a 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Driver event processing - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -53,12 +53,12 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { - struct os_time now; + struct os_reltime now; if (ssid == NULL || ssid->disabled_until.sec == 0) return 0; - os_get_time(&now); + os_get_reltime(&now); if (ssid->disabled_until.sec > now.sec) return ssid->disabled_until.sec - now.sec; @@ -978,9 +978,6 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request " "since there are no enabled networks"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); -#ifdef CONFIG_P2P - wpa_s->sta_scan_pending = 0; -#endif /* CONFIG_P2P */ return; } @@ -1181,7 +1178,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, union wpa_event_data *data, int own_request) { - struct wpa_scan_results *scan_res; + struct wpa_scan_results *scan_res = NULL; + int ret = 0; int ap = 0; #ifndef CONFIG_NO_RANDOM_POOL size_t i, num; @@ -1194,24 +1192,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpa_supplicant_notify_scanning(wpa_s, 0); -#ifdef CONFIG_P2P - if (own_request && wpa_s->global->p2p_cb_on_scan_complete && - !wpa_s->global->p2p_disabled && - wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending && - !wpa_s->scan_res_handler) { - wpa_s->global->p2p_cb_on_scan_complete = 0; - if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " - "stopped scan processing"); - wpa_s->scan_req = wpa_s->last_scan_req; - wpa_s->sta_scan_pending = 1; - wpa_supplicant_req_scan(wpa_s, 5, 0); - return -1; - } - } - wpa_s->sta_scan_pending = 0; -#endif /* CONFIG_P2P */ - scan_res = wpa_supplicant_get_scan_results(wpa_s, data ? &data->scan_info : NULL, 1); @@ -1224,7 +1204,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try " "scanning again"); wpa_supplicant_req_new_scan(wpa_s, 1, 0); - return -1; + ret = -1; + goto scan_work_done; } #ifndef CONFIG_NO_RANDOM_POOL @@ -1243,16 +1224,16 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_NO_RANDOM_POOL */ - if (own_request && wpa_s->scan_res_handler) { + if (own_request && wpa_s->scan_res_handler && + (wpa_s->own_scan_running || !wpa_s->external_scan_running)) { void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); scan_res_handler = wpa_s->scan_res_handler; wpa_s->scan_res_handler = NULL; scan_res_handler(wpa_s, scan_res); - - wpa_scan_results_free(scan_res); - return -2; + ret = -2; + goto scan_work_done; } if (ap) { @@ -1261,48 +1242,67 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, if (wpa_s->ap_iface->scan_cb) wpa_s->ap_iface->scan_cb(wpa_s->ap_iface); #endif /* CONFIG_AP */ - wpa_scan_results_free(scan_res); - return 0; + goto scan_work_done; } - wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available"); - wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)", + wpa_s->own_scan_running, wpa_s->external_scan_running); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", + wpa_s->manual_scan_id); + wpa_s->manual_scan_use_id = 0; + } else { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + } wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); - if (sme_proc_obss_scan(wpa_s) > 0) { + if (!wpa_s->own_scan_running && wpa_s->external_scan_running) { + wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection"); wpa_scan_results_free(scan_res); return 0; } - if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) { - wpa_scan_results_free(scan_res); - return 0; - } + if (sme_proc_obss_scan(wpa_s) > 0) + goto scan_work_done; - if (autoscan_notify_scan(wpa_s, scan_res)) { - wpa_scan_results_free(scan_res); - return 0; - } + if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) + goto scan_work_done; + + if (autoscan_notify_scan(wpa_s, scan_res)) + goto scan_work_done; if (wpa_s->disconnected) { wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); - wpa_scan_results_free(scan_res); - return 0; + goto scan_work_done; } if (!wpas_driver_bss_selection(wpa_s) && - bgscan_notify_scan(wpa_s, scan_res) == 1) { - wpa_scan_results_free(scan_res); - return 0; - } + bgscan_notify_scan(wpa_s, scan_res) == 1) + goto scan_work_done; wpas_wps_update_ap_info(wpa_s, scan_res); wpa_scan_results_free(scan_res); + if (wpa_s->scan_work) { + struct wpa_radio_work *work = wpa_s->scan_work; + wpa_s->scan_work = NULL; + radio_work_done(work); + } + return wpas_select_network_from_last_scan(wpa_s, 1, own_request); + +scan_work_done: + wpa_scan_results_free(scan_res); + if (wpa_s->scan_work) { + struct wpa_radio_work *work = wpa_s->scan_work; + wpa_s->scan_work = NULL; + radio_work_done(work); + } + return ret; } @@ -1381,6 +1381,16 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 1; } #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_WPS + if (wpa_s->after_wps > 0 || wpas_wps_searching(wpa_s)) { + wpa_dbg(wpa_s, MSG_DEBUG, "Use shorter wait during WPS processing"); + timeout_sec = 0; + timeout_usec = 500000; + wpa_supplicant_req_new_scan(wpa_s, timeout_sec, + timeout_usec); + return 0; + } +#endif /* CONFIG_WPS */ if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); @@ -1428,13 +1438,13 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s) #ifdef CONFIG_NO_SCAN_PROCESSING return -1; #else /* CONFIG_NO_SCAN_PROCESSING */ - struct os_time now; + struct os_reltime now; if (wpa_s->last_scan_res_used <= 0) return -1; - os_get_time(&now); - if (now.sec - wpa_s->last_scan.sec > 5) { + os_get_reltime(&now); + if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) { wpa_printf(MSG_DEBUG, "Fast associate: Old scan results"); return -1; } @@ -1955,9 +1965,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_s->last_eapol_matches_bssid = 0; if (wpa_s->pending_eapol_rx) { - struct os_time now, age; - os_get_time(&now); - os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age); + struct os_reltime now, age; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age); if (age.sec == 0 && age.usec < 100000 && os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) == 0) { @@ -2143,7 +2153,6 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, wpas_notify_disconnect_reason(wpa_s); if (wpa_supplicant_dynamic_keys(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys"); - wpa_s->keys_cleared = 0; wpa_clear_keys(wpa_s, wpa_s->bssid); } last_ssid = wpa_s->current_ssid; @@ -2187,13 +2196,13 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { int pairwise; - struct os_time t; + struct os_reltime t; wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected"); pairwise = (data && data->michael_mic_failure.unicast); - os_get_time(&t); - if ((wpa_s->last_michael_mic_error && - t.sec - wpa_s->last_michael_mic_error <= 60) || + os_get_reltime(&t); + if ((wpa_s->last_michael_mic_error.sec && + !os_reltime_expired(&t, &wpa_s->last_michael_mic_error, 60)) || wpa_s->pending_mic_error_report) { if (wpa_s->pending_mic_error_report) { /* @@ -2271,7 +2280,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, wpa_sm_key_request(wpa_s->wpa, 1, pairwise); #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ } - wpa_s->last_michael_mic_error = t.sec; + wpa_s->last_michael_mic_error = t; wpa_s->mic_errors_seen++; } @@ -2687,6 +2696,87 @@ static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s) } +static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, + const struct ieee80211_mgmt *mgmt, + size_t len, int freq) +{ + const u8 *payload; + size_t plen; + u8 category; + + if (len < IEEE80211_HDRLEN + 2) + return; + + payload = &mgmt->u.action.category; + category = *payload++; + plen = (((const u8 *) mgmt) + len) - payload; + + wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR + " Category=%u DataLen=%d freq=%d MHz", + MAC2STR(mgmt->sa), category, (int) plen, freq); + +#ifdef CONFIG_IEEE80211R + if (category == WLAN_ACTION_FT) { + ft_rx_action(wpa_s, payload, plen); + return; + } +#endif /* CONFIG_IEEE80211R */ + +#ifdef CONFIG_IEEE80211W +#ifdef CONFIG_SME + if (category == WLAN_ACTION_SA_QUERY) { + sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen); + return; + } +#endif /* CONFIG_SME */ +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_WNM + if (mgmt->u.action.category == WLAN_ACTION_WNM) { + ieee802_11_rx_wnm_action(wpa_s, mgmt, len); + return; + } +#endif /* CONFIG_WNM */ + +#ifdef CONFIG_GAS + if (mgmt->u.action.category == WLAN_ACTION_PUBLIC && + gas_query_rx(wpa_s->gas, mgmt->da, mgmt->sa, mgmt->bssid, + payload, plen, freq) == 0) + return; +#endif /* CONFIG_GAS */ + +#ifdef CONFIG_TDLS + if (category == WLAN_ACTION_PUBLIC && plen >= 4 && + payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) { + wpa_dbg(wpa_s, MSG_DEBUG, + "TDLS: Received Discovery Response from " MACSTR, + MAC2STR(mgmt->sa)); + return; + } +#endif /* CONFIG_TDLS */ + +#ifdef CONFIG_INTERWORKING + if (category == WLAN_ACTION_QOS && plen >= 1 && + payload[0] == QOS_QOS_MAP_CONFIG) { + const u8 *pos = payload + 1; + size_t qlen = plen - 1; + wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from " + MACSTR, MAC2STR(mgmt->sa)); + if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) == 0 && + qlen > 2 && pos[0] == WLAN_EID_QOS_MAP_SET && + pos[1] <= qlen - 2 && pos[1] >= 16) + wpas_qos_map_set(wpa_s, pos + 2, pos[1]); + return; + } +#endif /* CONFIG_INTERWORKING */ + +#ifdef CONFIG_P2P + wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, + category, payload, plen, freq); +#endif /* CONFIG_P2P */ +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { @@ -2740,11 +2830,44 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_supplicant_event_michael_mic_failure(wpa_s, data); break; #ifndef CONFIG_NO_SCAN_PROCESSING + case EVENT_SCAN_STARTED: + os_get_reltime(&wpa_s->scan_start_time); + if (wpa_s->own_scan_requested) { + struct os_reltime diff; + + os_reltime_sub(&wpa_s->scan_start_time, + &wpa_s->scan_trigger_time, &diff); + wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds", + diff.sec, diff.usec); + wpa_s->own_scan_requested = 0; + wpa_s->own_scan_running = 1; + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_use_id) { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED "id=%u", + wpa_s->manual_scan_id); + } else { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); + } + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan"); + wpa_s->external_scan_running = 1; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); + } + break; case EVENT_SCAN_RESULTS: + if (os_reltime_initialized(&wpa_s->scan_start_time)) { + struct os_reltime now, diff; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); + wpa_s->scan_start_time.sec = 0; + wpa_s->scan_start_time.usec = 0; + wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds", + diff.sec, diff.usec); + } wpa_supplicant_event_scan_results(wpa_s, data); - if (wpa_s->wpa_state != WPA_AUTHENTICATING && - wpa_s->wpa_state != WPA_ASSOCIATING) - wpas_p2p_continue_after_scan(wpa_s); + wpa_s->own_scan_running = 0; + wpa_s->external_scan_running = 0; + radio_work_check_next(wpa_s); break; #endif /* CONFIG_NO_SCAN_PROCESSING */ case EVENT_ASSOCINFO: @@ -2901,7 +3024,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.cf2); break; #endif /* CONFIG_AP */ -#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN) case EVENT_RX_MGMT: { u16 fc, stype; const struct ieee80211_mgmt *mgmt; @@ -2936,6 +3058,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } #endif /* CONFIG_IBSS_RSN */ + + if (stype == WLAN_FC_STYPE_ACTION) { + wpas_event_rx_mgmt_action( + wpa_s, mgmt, data->rx_mgmt.frame_len, + data->rx_mgmt.freq); + break; + } + wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received " "management frame in non-AP mode"); break; @@ -2958,79 +3088,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ break; } -#endif /* CONFIG_AP || CONFIG_IBSS_RSN */ - case EVENT_RX_ACTION: - wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR - " Category=%u DataLen=%d freq=%d MHz", - MAC2STR(data->rx_action.sa), - data->rx_action.category, (int) data->rx_action.len, - data->rx_action.freq); -#ifdef CONFIG_IEEE80211R - if (data->rx_action.category == WLAN_ACTION_FT) { - ft_rx_action(wpa_s, data->rx_action.data, - data->rx_action.len); - break; - } -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W -#ifdef CONFIG_SME - if (data->rx_action.category == WLAN_ACTION_SA_QUERY) { - sme_sa_query_rx(wpa_s, data->rx_action.sa, - data->rx_action.data, - data->rx_action.len); - break; - } -#endif /* CONFIG_SME */ -#endif /* CONFIG_IEEE80211W */ -#ifdef CONFIG_WNM - if (data->rx_action.category == WLAN_ACTION_WNM) { - ieee802_11_rx_wnm_action(wpa_s, &data->rx_action); - break; - } -#endif /* CONFIG_WNM */ -#ifdef CONFIG_GAS - if (data->rx_action.category == WLAN_ACTION_PUBLIC && - gas_query_rx(wpa_s->gas, data->rx_action.da, - data->rx_action.sa, data->rx_action.bssid, - data->rx_action.data, data->rx_action.len, - data->rx_action.freq) == 0) - break; -#endif /* CONFIG_GAS */ -#ifdef CONFIG_TDLS - if (data->rx_action.category == WLAN_ACTION_PUBLIC && - data->rx_action.len >= 4 && - data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) { - wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery " - "Response from " MACSTR, - MAC2STR(data->rx_action.sa)); - break; - } -#endif /* CONFIG_TDLS */ -#ifdef CONFIG_INTERWORKING - if (data->rx_action.category == WLAN_ACTION_QOS && - data->rx_action.len >= 1 && - data->rx_action.data[0] == QOS_QOS_MAP_CONFIG) { - const u8 *pos = data->rx_action.data + 1; - size_t len = data->rx_action.len - 1; - wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from " - MACSTR, MAC2STR(data->rx_action.sa)); - if (os_memcmp(data->rx_action.sa, wpa_s->bssid, - ETH_ALEN) == 0 && - len > 2 && pos[0] == WLAN_EID_QOS_MAP_SET && - pos[1] <= len - 2 && pos[1] >= 16) - wpas_qos_map_set(wpa_s, pos + 2, pos[1]); - break; - } -#endif /* CONFIG_INTERWORKING */ -#ifdef CONFIG_P2P - wpas_p2p_rx_action(wpa_s, data->rx_action.da, - data->rx_action.sa, - data->rx_action.bssid, - data->rx_action.category, - data->rx_action.data, - data->rx_action.len, data->rx_action.freq); -#endif /* CONFIG_P2P */ - break; case EVENT_RX_PROBE_REQ: if (data->rx_probe_req.sa == NULL || data->rx_probe_req.ie == NULL) @@ -3078,71 +3135,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s, data->remain_on_channel.freq); #endif /* CONFIG_P2P */ break; -#ifdef CONFIG_P2P - case EVENT_P2P_DEV_FOUND: { - struct p2p_peer_info peer_info; - - os_memset(&peer_info, 0, sizeof(peer_info)); - if (data->p2p_dev_found.dev_addr) - os_memcpy(peer_info.p2p_device_addr, - data->p2p_dev_found.dev_addr, ETH_ALEN); - if (data->p2p_dev_found.pri_dev_type) - os_memcpy(peer_info.pri_dev_type, - data->p2p_dev_found.pri_dev_type, - sizeof(peer_info.pri_dev_type)); - if (data->p2p_dev_found.dev_name) - os_strlcpy(peer_info.device_name, - data->p2p_dev_found.dev_name, - sizeof(peer_info.device_name)); - peer_info.config_methods = data->p2p_dev_found.config_methods; - peer_info.dev_capab = data->p2p_dev_found.dev_capab; - peer_info.group_capab = data->p2p_dev_found.group_capab; - - /* - * FIX: new_device=1 is not necessarily correct. We should - * maintain a P2P peer database in wpa_supplicant and update - * this information based on whether the peer is truly new. - */ - wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1); - break; - } - case EVENT_P2P_GO_NEG_REQ_RX: - wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src, - data->p2p_go_neg_req_rx.dev_passwd_id); - break; - case EVENT_P2P_GO_NEG_COMPLETED: - wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res); - break; - case EVENT_P2P_PROV_DISC_REQUEST: - wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer, - data->p2p_prov_disc_req.config_methods, - data->p2p_prov_disc_req.dev_addr, - data->p2p_prov_disc_req.pri_dev_type, - data->p2p_prov_disc_req.dev_name, - data->p2p_prov_disc_req.supp_config_methods, - data->p2p_prov_disc_req.dev_capab, - data->p2p_prov_disc_req.group_capab, - NULL, 0); - break; - case EVENT_P2P_PROV_DISC_RESPONSE: - wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer, - data->p2p_prov_disc_resp.config_methods); - break; - case EVENT_P2P_SD_REQUEST: - wpas_sd_request(wpa_s, data->p2p_sd_req.freq, - data->p2p_sd_req.sa, - data->p2p_sd_req.dialog_token, - data->p2p_sd_req.update_indic, - data->p2p_sd_req.tlvs, - data->p2p_sd_req.tlvs_len); - break; - case EVENT_P2P_SD_RESPONSE: - wpas_sd_response(wpa_s, data->p2p_sd_resp.sa, - data->p2p_sd_resp.update_indic, - data->p2p_sd_resp.tlvs, - data->p2p_sd_resp.tlvs_len); - break; -#endif /* CONFIG_P2P */ case EVENT_EAPOL_RX: wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src, data->eapol_rx.data, diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index f9885e39..f002fd50 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -2,6 +2,7 @@ * Generic advertisement service (GAS) query * Copyright (c) 2009, Atheros Communications * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -13,6 +14,7 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "common/gas.h" +#include "common/wpa_ctrl.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "offchannel.h" @@ -21,8 +23,6 @@ /** GAS query timeout in seconds */ #define GAS_QUERY_TIMEOUT_PERIOD 2 -/** Retry period for GAS query requests in milliseconds */ -#define GAS_SERVICE_RETRY_PERIOD_MS 500 /** @@ -30,6 +30,7 @@ */ struct gas_query_pending { struct dl_list list; + struct gas_query *gas; u8 addr[ETH_ALEN]; u8 dialog_token; u8 next_frag_id; @@ -54,12 +55,12 @@ struct gas_query { struct wpa_supplicant *wpa_s; struct dl_list pending; /* struct gas_query_pending */ struct gas_query_pending *current; + struct wpa_radio_work *work; }; static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); static void gas_query_timeout(void *eloop_data, void *user_ctx); -static void gas_service_timeout(void *eloop_data, void *user_ctx); /** @@ -82,24 +83,66 @@ struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s) } +static const char * gas_result_txt(enum gas_query_result result) +{ + switch (result) { + case GAS_QUERY_SUCCESS: + return "SUCCESS"; + case GAS_QUERY_FAILURE: + return "FAILURE"; + case GAS_QUERY_TIMEOUT: + return "TIMEOUT"; + case GAS_QUERY_PEER_ERROR: + return "PEER_ERROR"; + case GAS_QUERY_INTERNAL_ERROR: + return "INTERNAL_ERROR"; + case GAS_QUERY_CANCELLED: + return "CANCELLED"; + case GAS_QUERY_DELETED_AT_DEINIT: + return "DELETED_AT_DEINIT"; + } + + return "N/A"; +} + + +static void gas_query_free(struct gas_query_pending *query, int del_list) +{ + struct gas_query *gas = query->gas; + + if (del_list) + dl_list_del(&query->list); + + if (gas->work && gas->work->ctx == query) { + radio_work_done(gas->work); + gas->work = NULL; + } + + wpabuf_free(query->req); + wpabuf_free(query->adv_proto); + wpabuf_free(query->resp); + os_free(query); +} + + static void gas_query_done(struct gas_query *gas, struct gas_query_pending *query, enum gas_query_result result) { + wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR + " dialog_token=%u freq=%d status_code=%u result=%s", + MAC2STR(query->addr), query->dialog_token, query->freq, + query->status_code, gas_result_txt(result)); if (gas->current == query) gas->current = NULL; if (query->offchannel_tx_started) offchannel_send_action_done(gas->wpa_s); eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); eloop_cancel_timeout(gas_query_timeout, gas, query); - eloop_cancel_timeout(gas_service_timeout, gas, query); dl_list_del(&query->list); query->cb(query->ctx, query->addr, query->dialog_token, result, query->adv_proto, query->resp, query->status_code); - wpabuf_free(query->req); - wpabuf_free(query->adv_proto); - wpabuf_free(query->resp); - os_free(query); + gas_query_free(query, 0); } @@ -480,32 +523,36 @@ static void gas_query_timeout(void *eloop_data, void *user_ctx) } -static void gas_service_timeout(void *eloop_data, void *user_ctx) +static int gas_query_dialog_token_available(struct gas_query *gas, + const u8 *dst, u8 dialog_token) { - struct gas_query *gas = eloop_data; - struct wpa_supplicant *wpa_s = gas->wpa_s; - struct gas_query_pending *query = user_ctx; - int conn; - - conn = wpas_wpa_is_in_progress(wpa_s, 1); - if (conn || wpa_s->scanning || gas->current) { - wpa_printf(MSG_DEBUG, "GAS: Delaying GAS query Tx while another operation is in progress:%s%s%s", - conn ? " connection" : "", - wpa_s->scanning ? " scanning" : "", - gas->current ? " gas_query" : ""); - eloop_register_timeout( - GAS_SERVICE_RETRY_PERIOD_MS / 1000, - (GAS_SERVICE_RETRY_PERIOD_MS % 1000) * 1000, - gas_service_timeout, gas, query); + struct gas_query_pending *q; + dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { + if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && + dialog_token == q->dialog_token) + return 0; + } + + return 1; +} + + +static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) +{ + struct gas_query_pending *query = work->ctx; + struct gas_query *gas = query->gas; + + if (deinit) { + gas_query_free(query, 1); return; } + gas->work = work; + if (gas_query_tx(gas, query, query->req) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); - dl_list_del(&query->list); - wpabuf_free(query->req); - os_free(query); + gas_query_free(query, 1); return; } gas->current = query; @@ -514,20 +561,7 @@ static void gas_service_timeout(void *eloop_data, void *user_ctx) query->dialog_token); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); -} - -static int gas_query_dialog_token_available(struct gas_query *gas, - const u8 *dst, u8 dialog_token) -{ - struct gas_query_pending *q; - dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { - if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && - dialog_token == q->dialog_token) - return 0; - } - - return 1; } @@ -571,6 +605,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, if (query == NULL) return -1; + query->gas = gas; os_memcpy(query->addr, dst, ETH_ALEN); query->dialog_token = dialog_token; query->freq = freq; @@ -581,10 +616,15 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, *(wpabuf_mhead_u8(req) + 2) = dialog_token; - wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR - " dialog_token %u", MAC2STR(dst), dialog_token); + wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR + " dialog_token=%u freq=%d", + MAC2STR(query->addr), query->dialog_token, query->freq); - eloop_register_timeout(0, 0, gas_service_timeout, gas, query); + if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, + query) < 0) { + gas_query_free(query, 1); + return -1; + } return dialog_token; } @@ -605,9 +645,3 @@ void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token) gas_query_done(gas, query, GAS_QUERY_CANCELLED); } - - -int gas_query_in_progress(struct gas_query *gas) -{ - return gas->current != NULL; -} diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h index 6b6c77ce..5c3d161a 100644 --- a/wpa_supplicant/gas_query.h +++ b/wpa_supplicant/gas_query.h @@ -18,7 +18,6 @@ struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s); void gas_query_deinit(struct gas_query *gas); int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, const u8 *bssid, const u8 *data, size_t len, int freq); -int gas_query_in_progress(struct gas_query *gas); /** * enum gas_query_result - GAS query result diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 47ef35ec..3083dd80 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -590,7 +590,7 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) peer->authentication_status |= IBSS_RSN_AUTH_BY_US; return ibss_rsn_auth_init(ibss_rsn, peer); } else { - os_get_time(&peer->own_auth_tx); + os_get_reltime(&peer->own_auth_tx); eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL); } @@ -834,9 +834,9 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, if (peer && peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) { if (peer->own_auth_tx.sec) { - struct os_time now, diff; - os_get_time(&now); - os_time_sub(&now, &peer->own_auth_tx, &diff); + struct os_reltime now, diff; + os_get_reltime(&now); + os_reltime_sub(&now, &peer->own_auth_tx, &diff); if (diff.sec == 0 && diff.usec < 500000) { wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX", (int) diff.usec); diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h index 3089283f..67fae2d1 100644 --- a/wpa_supplicant/ibss_rsn.h +++ b/wpa_supplicant/ibss_rsn.h @@ -40,7 +40,7 @@ struct ibss_rsn_peer { struct wpa_state_machine *auth; int authentication_status; - struct os_time own_auth_tx; + struct os_reltime own_auth_tx; }; struct ibss_rsn { diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 93652d8f..da8971d9 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -1,6 +1,7 @@ /* * Interworking (IEEE 802.11u) * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -520,12 +521,13 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap) if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) return 0; /* method not supported */ - if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) { + if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP && + eap->method != EAP_TYPE_FAST) { /* Only tunneled methods with username/password supported */ return 0; } - if (eap->method == EAP_TYPE_PEAP) { + if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) { if (eap->inner_method && eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) return 0; @@ -1416,6 +1418,13 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) } break; case EAP_TYPE_PEAP: + case EAP_TYPE_FAST: + if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"", + 0) < 0) + goto fail; + if (wpa_config_set(ssid, "pac_file", + "\"blob://pac_interworking\"", 0) < 0) + goto fail; os_snprintf(buf, sizeof(buf), "\"auth=%s\"", eap_get_name(EAP_VENDOR_IETF, eap->inner_method ? @@ -2194,7 +2203,8 @@ static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s, } -int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) +int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, + int *freqs) { interworking_stop_fetch_anqp(wpa_s); wpa_s->network_select = 1; @@ -2206,6 +2216,8 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) wpa_s->scan_res_handler = interworking_scan_res_handler; wpa_s->normal_scans = 0; wpa_s->scan_req = MANUAL_SCAN_REQ; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; wpa_supplicant_req_scan(wpa_s, 0, 0); @@ -2220,6 +2232,7 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, const struct wpabuf *resp, u16 status_code) { struct wpa_supplicant *wpa_s = ctx; + struct wpabuf *n; wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR " dialog_token=%d status_code=%d resp_len=%d", @@ -2228,10 +2241,14 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, if (!resp) return; - wpabuf_free(wpa_s->last_gas_resp); - wpa_s->last_gas_resp = wpabuf_dup(resp); - if (wpa_s->last_gas_resp == NULL) + n = wpabuf_dup(resp); + if (n == NULL) return; + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = wpa_s->last_gas_resp; + os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN); + wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token; + wpa_s->last_gas_resp = n; os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN); wpa_s->last_gas_dialog_token = dialog_token; } diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index 4a4af827..c8e70938 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -22,7 +22,8 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *query); int interworking_fetch_anqp(struct wpa_supplicant *wpa_s); void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s); -int interworking_select(struct wpa_supplicant *wpa_s, int auto_select); +int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, + int *freqs); int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c index 39b837e5..37f0c781 100644 --- a/wpa_supplicant/main.c +++ b/wpa_supplicant/main.c @@ -16,8 +16,6 @@ #include "driver_i.h" #include "p2p_supplicant.h" -extern struct wpa_driver_ops *wpa_drivers[]; - static void usage(void) { diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index e6a88e63..41d5102c 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1,6 +1,7 @@ /* * wpa_supplicant - P2P * Copyright (c) 2009-2010, Atheros Communications + * Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -196,6 +197,12 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, { size_t i; + if (wpa_s->p2p_scan_work) { + struct wpa_radio_work *work = wpa_s->p2p_scan_work; + wpa_s->p2p_scan_work = NULL; + radio_work_done(work); + } + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; @@ -204,13 +211,13 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *bss = scan_res->res[i]; - struct os_time time_tmp_age, entry_ts; + struct os_reltime time_tmp_age, entry_ts; const u8 *ies; size_t ies_len; time_tmp_age.sec = bss->age / 1000; time_tmp_age.usec = (bss->age % 1000) * 1000; - os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts); + os_reltime_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts); ies = (const u8 *) (bss + 1); ies_len = bss->ie_len; @@ -234,94 +241,125 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, } +static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpa_driver_scan_params *params = work->ctx; + int ret; + + if (deinit) { + wpa_scan_free_params(params); + return; + } + + ret = wpa_drv_scan(wpa_s, params); + wpa_scan_free_params(params); + work->ctx = NULL; + if (ret) { + radio_work_done(work); + return; + } + + os_get_reltime(&wpa_s->scan_trigger_time); + wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; + wpa_s->own_scan_requested = 1; + wpa_s->p2p_scan_work = work; +} + + static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) { struct wpa_supplicant *wpa_s = ctx; - struct wpa_supplicant *ifs; - struct wpa_driver_scan_params params; - int ret; + struct wpa_driver_scan_params *params = NULL; struct wpabuf *wps_ie, *ies; - int social_channels[] = { 2412, 2437, 2462, 0, 0 }; size_t ielen; + u8 *n; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; - for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { - if (ifs->sta_scan_pending && - (wpas_scan_scheduled(ifs) || ifs->scanning) && - wpas_p2p_in_progress(wpa_s) == 2) { - wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow " - "pending station mode scan to be " - "completed on interface %s", ifs->ifname); - wpa_s->global->p2p_cb_on_scan_complete = 1; - wpa_supplicant_req_scan(ifs, 0, 0); - return 1; - } + if (wpa_s->p2p_scan_work) { + wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending"); + return -1; } - os_memset(¶ms, 0, sizeof(params)); + params = os_zalloc(sizeof(*params)); + if (params == NULL) + return -1; /* P2P Wildcard SSID */ - params.num_ssids = 1; - params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; - params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; + params->num_ssids = 1; + n = os_malloc(P2P_WILDCARD_SSID_LEN); + if (n == NULL) + goto fail; + os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN); + params->ssids[0].ssid = n; + params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->wps->dev.p2p = 1; wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, wpa_s->wps->uuid, WPS_REQ_ENROLLEE, num_req_dev_types, req_dev_types); if (wps_ie == NULL) - return -1; + goto fail; ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); if (ies == NULL) { wpabuf_free(wps_ie); - return -1; + goto fail; } wpabuf_put_buf(ies, wps_ie); wpabuf_free(wps_ie); p2p_scan_ie(wpa_s->global->p2p, ies, dev_id); - params.p2p_probe = 1; - params.extra_ies = wpabuf_head(ies); - params.extra_ies_len = wpabuf_len(ies); + params->p2p_probe = 1; + n = os_malloc(wpabuf_len(ies)); + if (n == NULL) { + wpabuf_free(ies); + goto fail; + } + os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies)); + params->extra_ies = n; + params->extra_ies_len = wpabuf_len(ies); + wpabuf_free(ies); switch (type) { case P2P_SCAN_SOCIAL: - params.freqs = social_channels; + params->freqs = os_malloc(4 * sizeof(int)); + if (params->freqs == NULL) + goto fail; + params->freqs[0] = 2412; + params->freqs[1] = 2437; + params->freqs[2] = 2462; + params->freqs[3] = 0; break; case P2P_SCAN_FULL: break; case P2P_SCAN_SOCIAL_PLUS_ONE: - social_channels[3] = freq; - params.freqs = social_channels; + params->freqs = os_malloc(5 * sizeof(int)); + if (params->freqs == NULL) + goto fail; + params->freqs[0] = 2412; + params->freqs[1] = 2437; + params->freqs[2] = 2462; + params->freqs[3] = freq; + params->freqs[4] = 0; break; } - ret = wpa_drv_scan(wpa_s, ¶ms); - - wpabuf_free(ies); - - if (ret) { - for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { - if (ifs->scanning || - ifs->scan_res_handler == wpas_p2p_scan_res_handler) { - wpa_s->global->p2p_cb_on_scan_complete = 1; - ret = 1; - break; - } - } - } else { - os_get_time(&wpa_s->scan_trigger_time); - wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; - } + radio_remove_unstarted_work(wpa_s, "p2p-scan"); + if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb, + params) < 0) + goto fail; + return 0; - return ret; +fail: + wpa_scan_free_params(params); + return -1; } @@ -488,6 +526,8 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, os_free(wpa_s->go_params); wpa_s->go_params = NULL; + wpa_s->waiting_presence_resp = 0; + wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network"); if (ssid && (ssid->p2p_group || ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION || @@ -510,7 +550,6 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, wpa_config_remove_network(wpa_s->conf, id); wpa_supplicant_clear_status(wpa_s); wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_s->sta_scan_pending = 0; } else { wpa_printf(MSG_DEBUG, "P2P: Temporary group network not " "found"); @@ -853,11 +892,37 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, network_id = ssid->id; if (!client) { wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0); - os_get_time(&wpa_s->global->p2p_go_wait_client); + os_get_reltime(&wpa_s->global->p2p_go_wait_client); } } +struct send_action_work { + unsigned int freq; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + size_t len; + unsigned int wait_time; + u8 buf[0]; +}; + + +static void wpas_p2p_send_action_work_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (!wpa_s->p2p_send_action_work) + return; + + wpa_printf(MSG_DEBUG, "P2P: Send Action frame radio work timed out"); + os_free(wpa_s->p2p_send_action_work->ctx); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; +} + + static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, @@ -868,10 +933,31 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, { enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS; + if (wpa_s->p2p_send_action_work) { + struct send_action_work *awork; + awork = wpa_s->p2p_send_action_work->ctx; + if (awork->wait_time == 0) { + os_free(awork); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; + } else { + /* + * In theory, this should not be needed, but number of + * places in the P2P code is still using non-zero wait + * time for the last Action frame in the sequence and + * some of these do not call send_action_done(). + */ + eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, + wpa_s, NULL); + eloop_register_timeout( + 0, awork->wait_time * 1000, + wpas_p2p_send_action_work_timeout, + wpa_s, NULL); + } + } + if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return; switch (result) { case OFFCHANNEL_SEND_ACTION_SUCCESS: @@ -901,11 +987,81 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, } +static void wpas_send_action_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct send_action_work *awork = work->ctx; + + if (deinit) { + os_free(awork); + return; + } + + if (offchannel_send_action(wpa_s, awork->freq, awork->dst, awork->src, + awork->bssid, awork->buf, awork->len, + awork->wait_time, + wpas_p2p_send_action_tx_status, 1) < 0) { + os_free(awork); + radio_work_done(work); + return; + } + wpa_s->p2p_send_action_work = work; +} + + +static int wpas_send_action_work(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, const u8 *buf, + size_t len, unsigned int wait_time) +{ + struct send_action_work *awork; + + if (wpa_s->p2p_send_action_work) { + wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending"); + return -1; + } + + awork = os_zalloc(sizeof(*awork) + len); + if (awork == NULL) + return -1; + + awork->freq = freq; + os_memcpy(awork->dst, dst, ETH_ALEN); + os_memcpy(awork->src, src, ETH_ALEN); + os_memcpy(awork->bssid, bssid, ETH_ALEN); + awork->len = len; + awork->wait_time = wait_time; + os_memcpy(awork->buf, buf, len); + + if (radio_add_work(wpa_s, freq, "p2p-send-action", 0, + wpas_send_action_cb, awork) < 0) { + os_free(awork); + return -1; + } + + return 0; +} + + static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time) { struct wpa_supplicant *wpa_s = ctx; + int listen_freq = -1, send_freq = -1; + + if (wpa_s->p2p_listen_work) + listen_freq = wpa_s->p2p_listen_work->freq; + if (wpa_s->p2p_send_action_work) + send_freq = wpa_s->p2p_send_action_work->freq; + if (listen_freq != (int) freq && send_freq != (int) freq) { + wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)", + listen_freq, send_freq); + return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf, + len, wait_time); + } + + wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX"); return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len, wait_time, wpas_p2p_send_action_tx_status, 1); @@ -915,6 +1071,15 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst, static void wpas_send_action_done(void *ctx) { struct wpa_supplicant *wpa_s = ctx; + + if (wpa_s->p2p_send_action_work) { + eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, + wpa_s, NULL); + os_free(wpa_s->p2p_send_action_work->ctx); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; + } + offchannel_send_action_done(wpa_s); } @@ -1030,7 +1195,7 @@ static void p2p_go_configured(void *ctx, void *data) " [PERSISTENT]" : ""); } - os_get_time(&wpa_s->global->p2p_go_wait_client); + os_get_reltime(&wpa_s->global->p2p_go_wait_client); if (params->persistent_group) { network_id = wpas_p2p_store_persistent_group( wpa_s->parent, ssid, @@ -1328,12 +1493,21 @@ void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s) wpa_s->parent, NULL); if (wpa_s->global->p2p) p2p_group_formation_failed(wpa_s->global->p2p); - else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - wpa_drv_p2p_group_formation_failed(wpa_s); wpas_group_formation_completed(wpa_s, 0); } +static void wpas_p2p_grpform_fail_after_wps(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "P2P: Reject group formation due to WPS provisioning failure"); + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + wpa_s->global->p2p_fail_on_wps_complete = 0; +} + + void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) { if (wpa_s->global->p2p_group_formation != wpa_s) @@ -1346,7 +1520,7 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) } -void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) +static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) { struct wpa_supplicant *wpa_s = ctx; @@ -1433,7 +1607,7 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) } -void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) +static void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) { struct wpa_supplicant *wpa_s = ctx; wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR @@ -1443,9 +1617,9 @@ void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) } -void wpas_dev_found(void *ctx, const u8 *addr, - const struct p2p_peer_info *info, - int new_device) +static void wpas_dev_found(void *ctx, const u8 *addr, + const struct p2p_peer_info *info, + int new_device) { #ifndef CONFIG_NO_STDOUT_DEBUG struct wpa_supplicant *wpa_s = ctx; @@ -1494,32 +1668,104 @@ static void wpas_find_stopped(void *ctx) } -static int wpas_start_listen(void *ctx, unsigned int freq, - unsigned int duration, - const struct wpabuf *probe_resp_ie) +struct wpas_p2p_listen_work { + unsigned int freq; + unsigned int duration; + struct wpabuf *probe_resp_ie; +}; + + +static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork) { - struct wpa_supplicant *wpa_s = ctx; + if (lwork == NULL) + return; + wpabuf_free(lwork->probe_resp_ie); + os_free(lwork); +} + + +static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s) +{ + struct wpas_p2p_listen_work *lwork; + + if (!wpa_s->p2p_listen_work) + return; + + lwork = wpa_s->p2p_listen_work->ctx; + wpas_p2p_listen_work_free(lwork); + radio_work_done(wpa_s->p2p_listen_work); + wpa_s->p2p_listen_work = NULL; +} + - wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL); +static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpas_p2p_listen_work *lwork = work->ctx; + + if (deinit) { + wpas_p2p_listen_work_free(lwork); + return; + } + + wpa_s->p2p_listen_work = work; + + wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL); if (wpa_drv_probe_req_report(wpa_s, 1) < 0) { wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to " "report received Probe Request frames"); - return -1; + wpas_p2p_listen_work_done(wpa_s); + return; } - wpa_s->pending_listen_freq = freq; - wpa_s->pending_listen_duration = duration; + wpa_s->pending_listen_freq = lwork->freq; + wpa_s->pending_listen_duration = lwork->duration; - if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) { + if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0) + { wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver " "to remain on channel (%u MHz) for Listen " - "state", freq); + "state", lwork->freq); + wpas_p2p_listen_work_done(wpa_s); wpa_s->pending_listen_freq = 0; - return -1; + return; } wpa_s->off_channel_freq = 0; - wpa_s->roc_waiting_drv_freq = freq; + wpa_s->roc_waiting_drv_freq = lwork->freq; +} + + +static int wpas_start_listen(void *ctx, unsigned int freq, + unsigned int duration, + const struct wpabuf *probe_resp_ie) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpas_p2p_listen_work *lwork; + + if (wpa_s->p2p_listen_work) { + wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists"); + return -1; + } + + lwork = os_zalloc(sizeof(*lwork)); + if (lwork == NULL) + return -1; + lwork->freq = freq; + lwork->duration = duration; + if (probe_resp_ie) { + lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie); + if (lwork->probe_resp_ie == NULL) { + wpas_p2p_listen_work_free(lwork); + return -1; + } + } + + if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb, + lwork) < 0) { + wpas_p2p_listen_work_free(lwork); + return -1; + } return 0; } @@ -1535,6 +1781,7 @@ static void wpas_stop_listen(void *ctx) } wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL); wpa_drv_probe_req_report(wpa_s, 0); + wpas_p2p_listen_work_done(wpa_s); } @@ -2035,8 +2282,8 @@ static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WIFI_DISPLAY */ -void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, - u16 update_indic, const u8 *tlvs, size_t tlvs_len) +static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, + u16 update_indic, const u8 *tlvs, size_t tlvs_len) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos = tlvs; @@ -2153,8 +2400,8 @@ done: } -void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, - const u8 *tlvs, size_t tlvs_len) +static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, + const u8 *tlvs, size_t tlvs_len) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos = tlvs; @@ -2221,8 +2468,6 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs); @@ -2254,8 +2499,6 @@ u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs); @@ -2333,8 +2576,6 @@ u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s, int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_sd_cancel_request(wpa_s, req); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; return p2p_sd_cancel_request(wpa_s->global->p2p, @@ -2346,11 +2587,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, const u8 *dst, u8 dialog_token, const struct wpabuf *resp_tlvs) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token, - resp_tlvs); - return; - } if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token, @@ -2360,10 +2596,6 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - wpa_drv_p2p_service_update(wpa_s); - return; - } if (wpa_s->global->p2p) p2p_sd_service_update(wpa_s->global->p2p); } @@ -2488,11 +2720,11 @@ static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s, } -void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, - const u8 *dev_addr, const u8 *pri_dev_type, - const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab, const u8 *group_id, - size_t group_id_len) +static void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, + const u8 *dev_addr, const u8 *pri_dev_type, + const char *dev_name, u16 supp_config_methods, + u8 dev_capab, u8 group_capab, const u8 *group_id, + size_t group_id_len) { struct wpa_supplicant *wpa_s = ctx; char devtype[WPS_DEV_TYPE_BUFSIZE]; @@ -2545,7 +2777,7 @@ void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, } -void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) +static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) { struct wpa_supplicant *wpa_s = ctx; unsigned int generated_pin = 0; @@ -3388,6 +3620,28 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s) } +static void wpas_presence_resp(void *ctx, const u8 *src, u8 status, + const u8 *noa, size_t noa_len) +{ + struct wpa_supplicant *wpa_s, *intf = ctx; + char hex[100]; + + for (wpa_s = intf->global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_s->waiting_presence_resp) + break; + } + if (!wpa_s) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No group interface was waiting for presence response"); + return; + } + wpa_s->waiting_presence_resp = 0; + + wpa_snprintf_hex(hex, sizeof(hex), noa, noa_len); + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PRESENCE_RESPONSE "src=" MACSTR + " status=%u noa=%s", MAC2STR(src), status, hex); +} + + /** * wpas_p2p_init - Initialize P2P module for %wpa_supplicant * @global: Pointer to global data from wpa_supplicant_init() @@ -3409,25 +3663,6 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) if (global->p2p) return 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - struct p2p_params params; - - wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management"); - os_memset(¶ms, 0, sizeof(params)); - params.dev_name = wpa_s->conf->device_name; - os_memcpy(params.pri_dev_type, wpa_s->conf->device_type, - WPS_DEV_TYPE_LEN); - params.num_sec_dev_types = wpa_s->conf->num_sec_device_types; - os_memcpy(params.sec_dev_type, - wpa_s->conf->sec_device_type, - params.num_sec_dev_types * WPS_DEV_TYPE_LEN); - - if (wpa_drv_p2p_set_params(wpa_s, ¶ms) < 0) - return -1; - - return 0; - } - os_memset(&p2p, 0, sizeof(p2p)); p2p.cb_ctx = wpa_s; p2p.debug_print = wpas_p2p_debug_print; @@ -3452,6 +3687,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.invitation_result = wpas_invitation_result; p2p.get_noa = wpas_get_noa; p2p.go_connected = wpas_go_connected; + p2p.presence_resp = wpas_presence_resp; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); @@ -3588,6 +3824,13 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); wpas_p2p_remove_pending_group_interface(wpa_s); eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL); + wpas_p2p_listen_work_done(wpa_s); + if (wpa_s->p2p_send_action_work) { + os_free(wpa_s->p2p_send_action_work->ctx); + radio_work_done(wpa_s->p2p_send_action_work); + wpa_s->p2p_send_action_work = NULL; + } + eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL); /* TODO: remove group interface from the driver if this wpa_s instance * is on top of a P2P group interface */ @@ -3672,12 +3915,6 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method, - go_intent, own_interface_addr, - force_freq, persistent_group); - } - /* * Increase GO config timeout if HT40 is used since it takes some time * to scan channels for coex purposes before the BSS can be started. @@ -3703,9 +3940,6 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; - return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, persistent_group, ssid ? ssid->ssid : NULL, @@ -3789,7 +4023,8 @@ static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s, return 0; } - updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update); + updated = os_reltime_before(&wpa_s->p2p_auto_started, + &bss->last_update); wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at " "%ld.%06ld (%supdated in last scan)", bss->last_update.sec, bss->last_update.usec, @@ -4044,8 +4279,9 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq) */ ret = wpa_drv_scan(wpa_s, ¶ms); if (!ret) { - os_get_time(&wpa_s->scan_trigger_time); + os_get_reltime(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_join; + wpa_s->own_scan_requested = 1; } wpabuf_free(ies); @@ -4287,6 +4523,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; + wpa_s->global->p2p_fail_on_wps_complete = 0; + if (go_intent < 0) go_intent = wpa_s->conf->p2p_go_intent; @@ -4331,7 +4569,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, dev_addr); } if (auto_join) { - os_get_time(&wpa_s->p2p_auto_started); + os_get_reltime(&wpa_s->p2p_auto_started); wpa_printf(MSG_DEBUG, "P2P: Auto join started at " "%ld.%06ld", wpa_s->p2p_auto_started.sec, @@ -4417,9 +4655,6 @@ static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, if (timeout > wpa_s->max_remain_on_chan) timeout = wpa_s->max_remain_on_chan; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_listen(wpa_s, timeout); - return p2p_listen(wpa_s->global->p2p, timeout); } @@ -4439,6 +4674,7 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback " "(p2p_long_listen=%d ms pending_action_tx=%p)", wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s)); + wpas_p2p_listen_work_done(wpa_s); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; if (p2p_listen_end(wpa_s->global->p2p, freq) > 0) @@ -4916,9 +5152,14 @@ static void wpas_p2p_idle_update(void *ctx, int idle) if (!wpa_s->ap_iface) return; wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not "); - if (idle) + if (idle) { + if (wpa_s->global->p2p_fail_on_wps_complete && + wpa_s->p2p_in_provisioning) { + wpas_p2p_grpform_fail_after_wps(wpa_s); + return; + } wpas_p2p_set_group_idle_timeout(wpa_s); - else + } else eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); } @@ -4929,8 +5170,6 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct p2p_group *group; struct p2p_group_config *cfg; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return NULL; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return NULL; @@ -5019,8 +5258,6 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, } if (wpa_s->global->p2p) p2p_wps_success_cb(wpa_s->global->p2p, peer_addr); - else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - wpa_drv_wps_success_cb(wpa_s, peer_addr); wpas_group_formation_completed(wpa_s, 1); } @@ -5041,6 +5278,31 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, } wpas_notify_p2p_wps_failed(wpa_s, fail); + + if (wpa_s == wpa_s->global->p2p_group_formation) { + /* + * Allow some time for the failed WPS negotiation exchange to + * complete, but remove the group since group formation cannot + * succeed after provisioning failure. + */ + wpa_printf(MSG_DEBUG, "P2P: WPS step failed during group formation - reject connection from timeout"); + wpa_s->global->p2p_fail_on_wps_complete = 1; + eloop_deplete_timeout(0, 50000, + wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); + } +} + + +int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->global->p2p_fail_on_wps_complete || + !wpa_s->p2p_in_provisioning) + return 0; + + wpas_p2p_grpform_fail_after_wps(wpa_s); + + return 1; } @@ -5073,7 +5335,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->auto_pd_scan_retry = 0; wpas_p2p_stop_find(wpa_s); wpa_s->p2p_join_scan_count = 0; - os_get_time(&wpa_s->p2p_auto_started); + os_get_reltime(&wpa_s->p2p_auto_started); wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld", wpa_s->p2p_auto_started.sec, wpa_s->p2p_auto_started.usec); @@ -5081,12 +5343,6 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return 0; } - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr, - config_methods, - use == WPAS_P2P_PD_FOR_JOIN); - } - if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) return -1; @@ -5122,9 +5378,6 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->p2p_long_listen = 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_find(wpa_s, timeout, type); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || wpa_s->p2p_in_provisioning) return -1; @@ -5143,12 +5396,6 @@ static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s) wpa_s->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); - wpa_s->global->p2p_cb_on_scan_complete = 0; - - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { - wpa_drv_p2p_stop_find(wpa_s); - return 1; - } if (wpa_s->global->p2p) p2p_stop_find(wpa_s->global->p2p); @@ -5302,9 +5549,6 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) { wpa_s->p2p_long_listen = 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_reject(wpa_s, addr); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5360,11 +5604,6 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (res) return res; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid, - ssid->ssid, ssid->ssid_len, - go_dev_addr, 1); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5442,11 +5681,6 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, } wpa_s->parent->pending_invite_ssid_id = -1; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid, - ssid->ssid, ssid->ssid_len, - go_dev_addr, persistent); - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5477,7 +5711,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) } if (!wpa_s->show_group_started || !ssid) - goto done; + return; wpa_s->show_group_started = 0; @@ -5519,17 +5753,14 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) if (network_id < 0) network_id = ssid->id; wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1); - -done: - wpas_p2p_continue_after_scan(wpa_s); } int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, u32 interval1, u32 duration2, u32 interval2) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; + int ret; + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5538,18 +5769,19 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, wpa_s->current_ssid->mode != WPAS_MODE_INFRA) return -1; - return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid, - wpa_s->own_addr, wpa_s->assoc_freq, - duration1, interval1, duration2, interval2); + ret = p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid, + wpa_s->own_addr, wpa_s->assoc_freq, + duration1, interval1, duration2, interval2); + if (ret == 0) + wpa_s->waiting_presence_resp = 1; + + return ret; } int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period, unsigned int interval) { - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -5651,8 +5883,6 @@ int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return 0; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return 0; if (!locally_generated) p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, @@ -5680,8 +5910,6 @@ void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return; if (!locally_generated) p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, @@ -5831,8 +6059,6 @@ int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled) { if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; - if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) - return -1; wpa_s->global->cross_connection = enabled; p2p_set_cross_connect(wpa_s->global->p2p, enabled); @@ -6090,7 +6316,7 @@ void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s, int freq_24, int freq_5, int freq_overall) { struct p2p_data *p2p = wpa_s->global->p2p; - if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)) + if (p2p == NULL) return; p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall); } @@ -6101,7 +6327,7 @@ int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr) u8 peer[ETH_ALEN]; struct p2p_data *p2p = wpa_s->global->p2p; - if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)) + if (p2p == NULL) return -1; if (hwaddr_aton(addr, peer)) @@ -6158,10 +6384,10 @@ int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s) } if (!ret && wpa_s->global->p2p_go_wait_client.sec) { - struct os_time now; - os_get_time(&now); - if (now.sec > wpa_s->global->p2p_go_wait_client.sec + - P2P_MAX_INITIAL_CONN_WAIT_GO) { + struct os_reltime now; + os_get_reltime(&now); + if (os_reltime_expired(&now, &wpa_s->global->p2p_go_wait_client, + P2P_MAX_INITIAL_CONN_WAIT_GO)) { /* Wait for the first client has expired */ wpa_s->global->p2p_go_wait_client.sec = 0; } else { @@ -6324,30 +6550,6 @@ unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s) } -void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s) -{ - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not " - "pending anymore (sta_scan_pending=%d " - "p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending, - wpa_s->global->p2p_cb_on_scan_complete); - wpa_s->sta_scan_pending = 0; - - if (!wpa_s->global->p2p_cb_on_scan_complete) - return; - wpa_s->global->p2p_cb_on_scan_complete = 0; - - if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) - return; - - if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { - wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " - "continued after successful connection"); - p2p_increase_search_delay(wpa_s->global->p2p, - wpas_p2p_search_delay(wpa_s)); - } -} - - static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s, struct wpa_ssid *s, const u8 *addr, int iface_addr) diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 9630eb5b..7abfb125 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -74,22 +74,7 @@ void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da, u8 category, const u8 *data, size_t len, int freq); void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies); void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s); -void wpas_dev_found(void *ctx, const u8 *addr, - const struct p2p_peer_info *info, - int new_device); void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s); -void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res); -void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id); -void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, - const u8 *dev_addr, const u8 *pri_dev_type, - const char *dev_name, u16 supp_config_methods, - u8 dev_capab, u8 group_capab, const u8 *group_id, - size_t group_id_len); -void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods); -void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, - u16 update_indic, const u8 *tlvs, size_t tlvs_len); -void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, - const u8 *tlvs, size_t tlvs_len); u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs); u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, @@ -143,6 +128,7 @@ int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr); int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s); void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); +int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s); int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s); void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -164,14 +150,9 @@ void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer, int iface_addr); #ifdef CONFIG_P2P -void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s); int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s); void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s); #else /* CONFIG_P2P */ -static inline void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s) -{ -} - static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s) { return 0; diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c index ff2ae747..ed570858 100644 --- a/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant/preauth_test.c @@ -27,9 +27,6 @@ #include "drivers/driver.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; - struct wpa_driver_ops *wpa_drivers[] = { NULL }; diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index f38dfbb2..da827bd7 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Scanning - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -21,7 +21,6 @@ #include "hs20_supplicant.h" #include "notify.h" #include "bss.h" -#include "gas_query.h" #include "scan.h" @@ -142,71 +141,37 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, } -static int int_array_len(const int *a) +static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) { - int i; - for (i = 0; a && a[i]; i++) - ; - return i; -} - - -static void int_array_concat(int **res, const int *a) -{ - int reslen, alen, i; - int *n; - - reslen = int_array_len(*res); - alen = int_array_len(a); + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpa_driver_scan_params *params = work->ctx; + int ret; - n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); - if (n == NULL) { - os_free(*res); - *res = NULL; + if (deinit) { + wpa_scan_free_params(params); return; } - for (i = 0; i <= alen; i++) - n[reslen + i] = a[i]; - *res = n; -} - - -static int freq_cmp(const void *a, const void *b) -{ - int _a = *(int *) a; - int _b = *(int *) b; - - if (_a == 0) - return 1; - if (_b == 0) - return -1; - return _a - _b; -} + wpa_supplicant_notify_scanning(wpa_s, 1); -static void int_array_sort_unique(int *a) -{ - int alen; - int i, j; - - if (a == NULL) + if (wpa_s->clear_driver_scan_cache) + params->only_new_results = 1; + ret = wpa_drv_scan(wpa_s, params); + wpa_scan_free_params(params); + work->ctx = NULL; + if (ret) { + wpa_supplicant_notify_scanning(wpa_s, 0); + wpas_notify_scan_done(wpa_s, 0); + radio_work_done(work); return; - - alen = int_array_len(a); - qsort(a, alen, sizeof(int), freq_cmp); - - i = 0; - j = 1; - while (a[i] && a[j]) { - if (a[i] == a[j]) { - j++; - continue; - } - a[++i] = a[j++]; } - if (a[i]) - i++; - a[i] = 0; + + os_get_reltime(&wpa_s->scan_trigger_time); + wpa_s->scan_runs++; + wpa_s->normal_scans++; + wpa_s->own_scan_requested = 1; + wpa_s->clear_driver_scan_cache = 0; + wpa_s->scan_work = work; } @@ -219,21 +184,24 @@ static void int_array_sort_unique(int *a) int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { - int ret; + struct wpa_driver_scan_params *ctx; - wpa_supplicant_notify_scanning(wpa_s, 1); + if (wpa_s->scan_work) { + wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending"); + return -1; + } - ret = wpa_drv_scan(wpa_s, params); - if (ret) { - wpa_supplicant_notify_scanning(wpa_s, 0); - wpas_notify_scan_done(wpa_s, 0); - } else { - os_get_time(&wpa_s->scan_trigger_time); - wpa_s->scan_runs++; - wpa_s->normal_scans++; + ctx = wpa_scan_clone_params(params); + if (ctx == NULL) + return -1; + + if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) + { + wpa_scan_free_params(ctx); + return -1; } - return ret; + return 0; } @@ -366,7 +334,8 @@ static void wpa_supplicant_optimize_freqs( if (params->freqs) params->freqs[0] = wpa_s->wps_freq; wpa_s->after_wps--; - } + } else if (wpa_s->after_wps) + wpa_s->after_wps--; if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq) { @@ -554,14 +523,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled"); - wpas_p2p_continue_after_scan(wpa_s); return; } if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); - wpas_p2p_continue_after_scan(wpa_s); return; } @@ -579,7 +546,6 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) wpa_s->scan_req == NORMAL_SCAN_REQ) { wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan"); wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); - wpas_p2p_continue_after_scan(wpa_s); return; } @@ -597,29 +563,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) } #ifdef CONFIG_P2P - if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) { - if (wpa_s->sta_scan_pending && - wpas_p2p_in_progress(wpa_s) == 2 && - wpa_s->global->p2p_cb_on_scan_complete) { - wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " - "mode scan during P2P search"); - } else { - wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " - "while P2P operation is in progress"); - wpa_s->sta_scan_pending = 1; - wpa_supplicant_req_scan(wpa_s, 5, 0); - return; - } - } -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_GAS - if (gas_query_in_progress(wpa_s->gas)) { - wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress"); - wpa_supplicant_req_scan(wpa_s, 1, 0); + if (wpas_p2p_in_progress(wpa_s)) { + wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress"); + wpa_supplicant_req_scan(wpa_s, 5, 0); return; } -#endif /* CONFIG_GAS */ +#endif /* CONFIG_P2P */ if (wpa_s->conf->ap_scan == 2) max_ssids = 1; @@ -766,6 +715,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in " "the scan request"); params.num_ssids++; + } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_passive && params.num_ssids == 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request"); } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; @@ -779,6 +731,17 @@ ssid_list_set: wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_only_new) + params.only_new_results = 1; + + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL && + wpa_s->manual_scan_freqs) { + wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels"); + params.freqs = wpa_s->manual_scan_freqs; + wpa_s->manual_scan_freqs = NULL; + } + if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); @@ -867,6 +830,13 @@ scan: ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); + if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && + !wpa_s->manual_scan_freqs) { + /* Restore manual_scan_freqs for the next attempt */ + wpa_s->manual_scan_freqs = params.freqs; + params.freqs = NULL; + } + wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); @@ -918,17 +888,19 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec) */ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) { - if (eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL)) - { - wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d sec %d usec", + int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s, + NULL); + if (res == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec", sec, usec); - return; + } else if (res == 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner", + sec, usec); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec", + sec, usec); + eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); } - - wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", - sec, usec); - eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); - eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); } @@ -1200,7 +1172,6 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) { wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request"); eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); - wpas_p2p_continue_after_scan(wpa_s); } @@ -1663,12 +1634,12 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, * Make sure we have a valid timestamp if the driver wrapper * does not set this. */ - os_get_time(&scan_res->fetch_time); + os_get_reltime(&scan_res->fetch_time); } filter_scan_res(wpa_s, scan_res); #ifdef CONFIG_WPS - if (wpas_wps_in_progress(wpa_s)) { + if (wpas_wps_searching(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS " "provisioning rules"); compar = wpa_scan_result_wps_compar; @@ -1720,9 +1691,21 @@ void scan_only_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received"); - wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", + wpa_s->manual_scan_id); + wpa_s->manual_scan_use_id = 0; + } else { + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + } wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); + if (wpa_s->scan_work) { + struct wpa_radio_work *work = wpa_s->scan_work; + wpa_s->scan_work = NULL; + radio_work_done(work); + } } @@ -1730,3 +1713,82 @@ int wpas_scan_scheduled(struct wpa_supplicant *wpa_s) { return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL); } + + +struct wpa_driver_scan_params * +wpa_scan_clone_params(const struct wpa_driver_scan_params *src) +{ + struct wpa_driver_scan_params *params; + size_t i; + u8 *n; + + params = os_zalloc(sizeof(*params)); + if (params == NULL) + return NULL; + + for (i = 0; i < src->num_ssids; i++) { + if (src->ssids[i].ssid) { + n = os_malloc(src->ssids[i].ssid_len); + if (n == NULL) + goto failed; + os_memcpy(n, src->ssids[i].ssid, + src->ssids[i].ssid_len); + params->ssids[i].ssid = n; + params->ssids[i].ssid_len = src->ssids[i].ssid_len; + } + } + params->num_ssids = src->num_ssids; + + if (src->extra_ies) { + n = os_malloc(src->extra_ies_len); + if (n == NULL) + goto failed; + os_memcpy(n, src->extra_ies, src->extra_ies_len); + params->extra_ies = n; + params->extra_ies_len = src->extra_ies_len; + } + + if (src->freqs) { + int len = int_array_len(src->freqs); + params->freqs = os_malloc((len + 1) * sizeof(int)); + if (params->freqs == NULL) + goto failed; + os_memcpy(params->freqs, src->freqs, (len + 1) * sizeof(int)); + } + + if (src->filter_ssids) { + params->filter_ssids = os_malloc(sizeof(params->filter_ssids) * + src->num_filter_ssids); + if (params->filter_ssids == NULL) + goto failed; + os_memcpy(params->filter_ssids, src->filter_ssids, + sizeof(params->filter_ssids) * src->num_filter_ssids); + params->num_filter_ssids = src->num_filter_ssids; + } + + params->filter_rssi = src->filter_rssi; + params->p2p_probe = src->p2p_probe; + params->only_new_results = src->only_new_results; + + return params; + +failed: + wpa_scan_free_params(params); + return NULL; +} + + +void wpa_scan_free_params(struct wpa_driver_scan_params *params) +{ + size_t i; + + if (params == NULL) + return; + + for (i = 0; i < params->num_ssids; i++) + os_free((u8 *) params->ssids[i].ssid); + os_free((u8 *) params->extra_ies); + os_free(params->freqs); + os_free(params->filter_ssids); + os_free(params); +} diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index b6fe070e..e4c89895 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -1,6 +1,6 @@ /* * WPA Supplicant - Scanning - * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -43,5 +43,8 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params, int interval); int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s); +struct wpa_driver_scan_params * +wpa_scan_clone_params(const struct wpa_driver_scan_params *src); +void wpa_scan_free_params(struct wpa_driver_scan_params *params); #endif /* SCAN_H */ diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 87c14ae3..43f40cd1 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1,6 +1,6 @@ /* * wpa_supplicant - SME - * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -157,6 +157,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (bss == NULL) { wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for " "the network"); + wpas_connect_work_done(wpa_s); return; } @@ -244,6 +245,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, &wpa_s->sme.assoc_req_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " "key management and encryption suites"); + wpas_connect_work_done(wpa_s); return; } } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && @@ -263,6 +265,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " "key management and encryption suites (no " "scan results)"); + wpas_connect_work_done(wpa_s); return; } #ifdef CONFIG_WPS @@ -386,8 +389,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, bss->bssid); else resp = sme_auth_build_sae_confirm(wpa_s); - if (resp == NULL) + if (resp == NULL) { + wpas_connect_work_done(wpa_s); return; + } params.sae_data = wpabuf_head(resp); params.sae_data_len = wpabuf_len(resp); wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED; @@ -417,6 +422,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpas_connection_failed(wpa_s, bss->bssid); wpa_supplicant_mark_disassoc(wpa_s); wpabuf_free(resp); + wpas_connect_work_done(wpa_s); return; } @@ -432,15 +438,56 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } +static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_connect_work *cwork = work->ctx; + struct wpa_supplicant *wpa_s = work->wpa_s; + + if (deinit) { + wpas_connect_work_free(cwork); + return; + } + + wpa_s->connect_work = work; + + if (!wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt"); + wpas_connect_work_done(wpa_s); + return; + } + + sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1); +} + + void sme_authenticate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { + struct wpa_connect_work *cwork; + + if (bss == NULL || ssid == NULL) + return; + if (wpa_s->connect_work) { + wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reject sme_authenticate() call since connect_work exist"); + return; + } + + cwork = os_zalloc(sizeof(*cwork)); + if (cwork == NULL) + return; + cwork->bss = bss; + cwork->ssid = ssid; + cwork->sme = 1; + #ifdef CONFIG_SAE wpa_s->sme.sae.state = SAE_NOTHING; wpa_s->sme.sae.send_confirm = 0; wpa_s->sme.sae_group_index = 0; #endif /* CONFIG_SAE */ - sme_send_authentication(wpa_s, bss, ssid, 1); + + if (radio_add_work(wpa_s, bss->freq, "sme-connect", 1, + sme_auth_start_cb, cwork) < 0) + wpas_connect_work_free(cwork); } @@ -651,9 +698,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; - params.pairwise_suite = - wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher); - params.group_suite = wpa_cipher_to_suite_driver(wpa_s->group_cipher); + params.pairwise_suite = wpa_s->pairwise_cipher; + params.group_suite = wpa_s->group_cipher; #ifdef CONFIG_HT_OVERRIDES os_memset(&htcaps, 0, sizeof(htcaps)); os_memset(&htcaps_mask, 0, sizeof(htcaps_mask)); @@ -1151,9 +1197,9 @@ static const unsigned int sa_query_retry_timeout = 201; static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s) { u32 tu; - struct os_time now, passed; - os_get_time(&now); - os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed); + struct os_reltime now, passed; + os_get_reltime(&now); + os_reltime_sub(&now, &wpa_s->sme.sa_query_start, &passed); tu = (passed.sec * 1000000 + passed.usec) / 1024; if (sa_query_max_timeout < tu) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out"); @@ -1203,7 +1249,7 @@ static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx) return; if (wpa_s->sme.sa_query_count == 0) { /* Starting a new SA Query procedure */ - os_get_time(&wpa_s->sme.sa_query_start); + os_get_reltime(&wpa_s->sme.sa_query_start); } trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; wpa_s->sme.sa_query_trans_id = nbuf; diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c index 484a4068..39971f28 100644 --- a/wpa_supplicant/tests/test_wpa.c +++ b/wpa_supplicant/tests/test_wpa.c @@ -17,10 +17,6 @@ #include "ap/wpa_auth.h" -extern int wpa_debug_level; -extern int wpa_debug_show_keys; - - struct wpa { u8 auth_addr[ETH_ALEN]; u8 supp_addr[ETH_ALEN]; diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 4f8d895a..65b27838 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -181,7 +181,7 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, /* Install GTK/IGTK */ /* point to key data field */ - ptr = (u8 *) frm + 1 + 1 + 2; + ptr = (u8 *) frm + 1 + 2; end = ptr + key_len_total; wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); @@ -237,16 +237,16 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data | * WNM-Sleep Mode IE | TFS Response IE */ - u8 *pos = (u8 *) frm; /* point to action field */ + u8 *pos = (u8 *) frm; /* point to payload after the action field */ u16 key_len_total = le_to_host16(*((u16 *)(frm+2))); struct wnm_sleep_element *wnmsleep_ie = NULL; /* multiple TFS Resp IE (assuming consecutive) */ u8 *tfsresp_ie_start = NULL; u8 *tfsresp_ie_end = NULL; - wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d", - frm[0], frm[1], key_len_total); - pos += 4 + key_len_total; + wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", + frm[0], key_len_total); + pos += 3 + key_len_total; if (pos > frm + len) { wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); return; @@ -473,6 +473,10 @@ static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, if (scan_res == NULL || num_neigh_rep == 0) return 0; + wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", + MAC2STR(wpa_s->bssid), + wpa_s->current_bss ? wpa_s->current_bss->level : 0); + for (i = 0; i < num_neigh_rep; i++) { for (j = 0; j < scan_res->num; j++) { /* Check for a better RSSI AP */ @@ -483,8 +487,16 @@ static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, /* Got a BSSID with better RSSI value */ os_memcpy(bssid_to_connect, neigh_rep[i].bssid, ETH_ALEN); + wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR + " with better scan RSSI %d", + MAC2STR(scan_res->res[j]->bssid), + scan_res->res[j]->level); return 1; } + wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR + " RSSI %d", j, + MAC2STR(scan_res->res[j]->bssid), + scan_res->res[j]->level); } } @@ -521,6 +533,14 @@ static void wnm_send_bss_transition_mgmt_resp( if (target_bssid) { os_memcpy(pos, target_bssid, ETH_ALEN); pos += ETH_ALEN; + } else if (status == WNM_BSS_TM_ACCEPT) { + /* + * P802.11-REVmc clarifies that the Target BSSID field is always + * present when status code is zero, so use a fake value here if + * no BSSID is yet known. + */ + os_memset(pos, 0, ETH_ALEN); + pos += ETH_ALEN; } len = pos - (u8 *) &mgmt->u.action.category; @@ -562,7 +582,7 @@ void wnm_scan_response(struct wpa_supplicant *wpa_s, wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, - 0, NULL); + 0, bssid); } wpa_s->reassociate = 1; @@ -717,7 +737,7 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; - mgmt->u.action.u.bss_tm_query.dialog_token = 0; + mgmt->u.action.u.bss_tm_query.dialog_token = 1; mgmt->u.action.u.bss_tm_query.query_reason = query_reason; pos = mgmt->u.action.u.bss_tm_query.variable; @@ -732,22 +752,23 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, - struct rx_action *action) + const struct ieee80211_mgmt *mgmt, size_t len) { const u8 *pos, *end; u8 act; - if (action->data == NULL || action->len == 0) + if (len < IEEE80211_HDRLEN + 2) return; - pos = action->data; - end = pos + action->len; + pos = &mgmt->u.action.category; + pos++; act = *pos++; + end = ((const u8 *) mgmt) + len; wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, - act, MAC2STR(action->sa)); + act, MAC2STR(mgmt->sa)); if (wpa_s->wpa_state < WPA_ASSOCIATED || - os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) { + os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " "frame"); return; @@ -756,10 +777,10 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, switch (act) { case WNM_BSS_TRANS_MGMT_REQ: ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, - !(action->da[0] & 0x01)); + !(mgmt->da[0] & 0x01)); break; case WNM_SLEEP_MODE_RESP: - ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len); + ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); break; default: wpa_printf(MSG_ERROR, "WNM: Unknown request"); diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index 2933926c..de873015 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -9,9 +9,6 @@ #ifndef WNM_STA_H #define WNM_STA_H -struct rx_action; -struct wpa_supplicant; - struct tsf_info { u8 present; u8 tsf_offset[2]; @@ -78,7 +75,7 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, u8 action, u16 intval, struct wpabuf *tfs_req); void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, - struct rx_action *action); + const struct ieee80211_mgmt *mgmt, size_t len); void wnm_scan_response(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index aabaa3cc..358c2feb 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -28,7 +28,7 @@ static const char *wpa_cli_version = "wpa_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors"; static const char *wpa_cli_license = @@ -2426,6 +2426,12 @@ static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv); +} + + enum wpa_cli_cmd_flags { cli_cmd_flag_none = 0x00, cli_cmd_flag_sensitive = 0x01 @@ -2893,6 +2899,8 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none, "<command> = driver private commands" }, #endif /* ANDROID */ + { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none, + "= radio_work <show/add/done>" }, { NULL, NULL, NULL, cli_cmd_flag_none, NULL } }; diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c index 4afaae90..5426177a 100644 --- a/wpa_supplicant/wpa_priv.c +++ b/wpa_supplicant/wpa_priv.c @@ -552,8 +552,6 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) } -extern struct wpa_driver_ops *wpa_drivers[]; - static struct wpa_priv_interface * wpa_priv_interface_init(const char *dir, const char *params) { @@ -946,8 +944,6 @@ static void usage(void) } -extern int wpa_debug_level; - int main(int argc, char *argv[]) { int c, i; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 2d6272b1..187e5d9b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -54,7 +54,7 @@ const char *wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors"; const char *wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" @@ -104,11 +104,6 @@ const char *wpa_supplicant_full_license5 = "\n"; #endif /* CONFIG_NO_STDOUT_DEBUG */ -extern int wpa_debug_level; -extern int wpa_debug_show_keys; -extern int wpa_debug_timestamp; -extern struct wpa_driver_ops *wpa_drivers[]; - /* Configure default/group WEP keys for static WEP */ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -200,8 +195,6 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) * So, wait a second until scanning again. */ wpa_supplicant_req_scan(wpa_s, 1, 0); - - wpas_p2p_continue_after_scan(wpa_s); } @@ -459,6 +452,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + gas_query_deinit(wpa_s->gas); wpa_s->gas = NULL; @@ -481,6 +477,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->ext_pw = NULL; wpabuf_free(wpa_s->last_gas_resp); + wpa_s->last_gas_resp = NULL; + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = NULL; os_free(wpa_s->last_scan_res); wpa_s->last_scan_res = NULL; @@ -497,29 +496,23 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) */ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) { - if (wpa_s->keys_cleared) { - /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have - * timing issues with keys being cleared just before new keys - * are set or just after association or something similar. This - * shows up in group key handshake failing often because of the - * client not receiving the first encrypted packets correctly. - * Skipping some of the extra key clearing steps seems to help - * in completing group key handshake more reliably. */ - wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - " - "skip key clearing"); - return; - } + int i, max; - /* MLME-DELETEKEYS.request */ - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0); #ifdef CONFIG_IEEE80211W - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0); + max = 6; +#else /* CONFIG_IEEE80211W */ + max = 4; #endif /* CONFIG_IEEE80211W */ - if (addr) { + + /* MLME-DELETEKEYS.request */ + for (i = 0; i < max; i++) { + if (wpa_s->keys_cleared & BIT(i)) + continue; + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0, + NULL, 0); + } + if (!(wpa_s->keys_cleared & BIT(0)) && addr && + !is_zero_ether_addr(addr)) { wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0); /* MLME-SETPROTECTION.request(None) */ @@ -528,7 +521,7 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) MLME_SETPROTECTION_PROTECT_TYPE_NONE, MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); } - wpa_s->keys_cleared = 1; + wpa_s->keys_cleared = (u32) -1; } @@ -659,6 +652,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_supplicant_state_txt(state)); + if (state == WPA_COMPLETED) + wpas_connect_work_done(wpa_s); + if (state != WPA_SCANNING) wpa_supplicant_notify_scanning(wpa_s, 0); @@ -699,7 +695,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, #ifdef CONFIG_BGSCAN if (state == WPA_COMPLETED) wpa_supplicant_start_bgscan(wpa_s); - else + else if (state < WPA_ASSOCIATED) wpa_supplicant_stop_bgscan(wpa_s); #endif /* CONFIG_BGSCAN */ @@ -725,6 +721,7 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global) #ifdef CONFIG_WPS struct wpa_supplicant *wpa_s = global->ifaces; while (wpa_s) { + struct wpa_supplicant *next = wpa_s->next; #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE || (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)) @@ -732,7 +729,7 @@ void wpa_supplicant_terminate_proc(struct wpa_global *global) #endif /* CONFIG_P2P */ if (wpas_wps_terminate_pending(wpa_s) == 1) pending = 1; - wpa_s = wpa_s->next; + wpa_s = next; } #endif /* CONFIG_WPS */ if (pending) @@ -861,34 +858,6 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx) } -enum wpa_key_mgmt key_mgmt2driver(int key_mgmt) -{ - switch (key_mgmt) { - case WPA_KEY_MGMT_NONE: - return KEY_MGMT_NONE; - case WPA_KEY_MGMT_IEEE8021X_NO_WPA: - return KEY_MGMT_802_1X_NO_WPA; - case WPA_KEY_MGMT_IEEE8021X: - return KEY_MGMT_802_1X; - case WPA_KEY_MGMT_WPA_NONE: - return KEY_MGMT_WPA_NONE; - case WPA_KEY_MGMT_FT_IEEE8021X: - return KEY_MGMT_FT_802_1X; - case WPA_KEY_MGMT_FT_PSK: - return KEY_MGMT_FT_PSK; - case WPA_KEY_MGMT_IEEE8021X_SHA256: - return KEY_MGMT_802_1X_SHA256; - case WPA_KEY_MGMT_PSK_SHA256: - return KEY_MGMT_PSK_SHA256; - case WPA_KEY_MGMT_WPS: - return KEY_MGMT_WPS; - case WPA_KEY_MGMT_PSK: - default: - return KEY_MGMT_PSK; - } -} - - static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_ie_data *ie) @@ -1229,7 +1198,8 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) break; case 4: /* Bits 32-39 */ #ifdef CONFIG_INTERWORKING - *pos |= 0x01; /* Bit 32 - QoS Map */ + if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING) + *pos |= 0x01; /* Bit 32 - QoS Map */ #endif /* CONFIG_INTERWORKING */ break; case 5: /* Bits 40-47 */ @@ -1270,6 +1240,70 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf) } +static int wpas_valid_bss(struct wpa_supplicant *wpa_s, + struct wpa_bss *test_bss) +{ + struct wpa_bss *bss; + + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + if (bss == test_bss) + return 1; + } + + return 0; +} + + +static int wpas_valid_ssid(struct wpa_supplicant *wpa_s, + struct wpa_ssid *test_ssid) +{ + struct wpa_ssid *ssid; + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (ssid == test_ssid) + return 1; + } + + return 0; +} + + +int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss, + struct wpa_ssid *test_ssid) +{ + if (test_bss && !wpas_valid_bss(wpa_s, test_bss)) + return 0; + + return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid); +} + + +void wpas_connect_work_free(struct wpa_connect_work *cwork) +{ + if (cwork == NULL) + return; + os_free(cwork); +} + + +void wpas_connect_work_done(struct wpa_supplicant *wpa_s) +{ + struct wpa_connect_work *cwork; + struct wpa_radio_work *work = wpa_s->connect_work; + + if (!work) + return; + + wpa_s->connect_work = NULL; + cwork = work->ctx; + work->ctx = NULL; + wpas_connect_work_free(cwork); + radio_work_done(work); +} + + +static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit); + /** * wpa_supplicant_associate - Request association * @wpa_s: Pointer to wpa_supplicant data @@ -1281,19 +1315,7 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf) void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { - u8 wpa_ie[200]; - size_t wpa_ie_len; - int use_crypt, ret, i, bssid_changed; - int algs = WPA_AUTH_ALG_OPEN; - enum wpa_cipher cipher_pairwise, cipher_group; - struct wpa_driver_associate_params params; - int wep_keys_set = 0; - int assoc_failed = 0; - struct wpa_ssid *old_ssid; -#ifdef CONFIG_HT_OVERRIDES - struct ieee80211_ht_capabilities htcaps; - struct ieee80211_ht_capabilities htcaps_mask; -#endif /* CONFIG_HT_OVERRIDES */ + struct wpa_connect_work *cwork; #ifdef CONFIG_IBSS_RSN ibss_rsn_deinit(wpa_s->ibss_rsn); @@ -1334,6 +1356,58 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } + if (wpa_s->connect_work) { + wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist"); + return; + } + + cwork = os_zalloc(sizeof(*cwork)); + if (cwork == NULL) + return; + + cwork->bss = bss; + cwork->ssid = ssid; + + if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1, + wpas_start_assoc_cb, cwork) < 0) { + os_free(cwork); + } +} + + +static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_connect_work *cwork = work->ctx; + struct wpa_bss *bss = cwork->bss; + struct wpa_ssid *ssid = cwork->ssid; + struct wpa_supplicant *wpa_s = work->wpa_s; + u8 wpa_ie[200]; + size_t wpa_ie_len; + int use_crypt, ret, i, bssid_changed; + int algs = WPA_AUTH_ALG_OPEN; + unsigned int cipher_pairwise, cipher_group; + struct wpa_driver_associate_params params; + int wep_keys_set = 0; + int assoc_failed = 0; + struct wpa_ssid *old_ssid; +#ifdef CONFIG_HT_OVERRIDES + struct ieee80211_ht_capabilities htcaps; + struct ieee80211_ht_capabilities htcaps_mask; +#endif /* CONFIG_HT_OVERRIDES */ + + if (deinit) { + wpas_connect_work_free(cwork); + return; + } + + wpa_s->connect_work = work; + + if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt"); + wpas_connect_work_done(wpa_s); + return; + } + os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; if (bss && !wpas_driver_bss_selection(wpa_s)) { @@ -1526,8 +1600,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); use_crypt = 1; - cipher_pairwise = wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher); - cipher_group = wpa_cipher_to_suite_driver(wpa_s->group_cipher); + cipher_pairwise = wpa_s->pairwise_cipher; + cipher_group = wpa_s->group_cipher; if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) @@ -1551,7 +1625,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, /* Assume that dynamic WEP-104 keys will be used and * set cipher suites in order for drivers to expect * encryption. */ - cipher_pairwise = cipher_group = CIPHER_WEP104; + cipher_pairwise = cipher_group = WPA_CIPHER_WEP104; } } #endif /* IEEE8021X_EAPOL */ @@ -1592,7 +1666,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, params.wpa_ie_len = wpa_ie_len; params.pairwise_suite = cipher_pairwise; params.group_suite = cipher_group; - params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt); + params.key_mgmt_suite = wpa_s->key_mgmt; params.wpa_proto = wpa_s->wpa_proto; params.auth_alg = algs; params.mode = ssid->mode; @@ -1605,8 +1679,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, params.wep_tx_keyidx = ssid->wep_tx_keyidx; if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && - (params.key_mgmt_suite == KEY_MGMT_PSK || - params.key_mgmt_suite == KEY_MGMT_FT_PSK)) { + (params.key_mgmt_suite == WPA_KEY_MGMT_PSK || + params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { params.passphrase = ssid->passphrase; if (ssid->psk_set) params.psk = ssid->psk; @@ -2323,6 +2397,16 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); +#ifdef CONFIG_PEERKEY + if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid && + wpa_s->current_ssid->peerkey && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && + wpa_sm_rx_eapol_peerkey(wpa_s->wpa, src_addr, buf, len) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Processed PeerKey EAPOL-Key"); + return; + } +#endif /* CONFIG_PEERKEY */ + if (wpa_s->wpa_state < WPA_ASSOCIATED || (wpa_s->last_eapol_matches_bssid && #ifdef CONFIG_AP @@ -2348,7 +2432,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len); if (wpa_s->pending_eapol_rx) { - os_get_time(&wpa_s->pending_eapol_rx_time); + os_get_reltime(&wpa_s->pending_eapol_rx_time); os_memcpy(wpa_s->pending_eapol_rx_src, src_addr, ETH_ALEN); } @@ -2918,12 +3002,89 @@ static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s, if (rn) os_strlcpy(radio->name, rn, sizeof(radio->name)); dl_list_init(&radio->ifaces); + dl_list_init(&radio->work); dl_list_add(&radio->ifaces, &wpa_s->radio_list); return radio; } +static void radio_work_free(struct wpa_radio_work *work) +{ + if (work->wpa_s->scan_work == work) { + /* This should not really happen. */ + wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work", + work->type, work, work->started); + work->wpa_s->scan_work = NULL; + } + +#ifdef CONFIG_P2P + if (work->wpa_s->p2p_scan_work == work) { + /* This should not really happen. */ + wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work", + work->type, work, work->started); + work->wpa_s->p2p_scan_work = NULL; + } +#endif /* CONFIG_P2P */ + + dl_list_del(&work->list); + os_free(work); +} + + +static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_radio *radio = eloop_ctx; + struct wpa_radio_work *work; + struct os_reltime now, diff; + struct wpa_supplicant *wpa_s; + + work = dl_list_first(&radio->work, struct wpa_radio_work, list); + if (work == NULL) + return; + + if (work->started) + return; /* already started and still in progress */ + + wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant, + radio_list); + if (wpa_s && wpa_s->external_scan_running) { + wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes"); + return; + } + + os_get_reltime(&now); + os_reltime_sub(&now, &work->time, &diff); + wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait", + work->type, work, diff.sec, diff.usec); + work->started = 1; + work->time = now; + work->cb(work, 0); +} + + +void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s, const char *type) +{ + struct wpa_radio_work *work, *tmp; + struct wpa_radio *radio = wpa_s->radio; + + dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work, + list) { + if (type && (work->started || os_strcmp(type, work->type) != 0)) + continue; + if (work->started) { + wpa_dbg(wpa_s, MSG_DEBUG, "Leaving started radio work '%s'@%p in the list", + work->type, work); + continue; + } + wpa_dbg(wpa_s, MSG_DEBUG, "Remove unstarted radio work '%s'@%p", + work->type, work); + work->cb(work, 1); + radio_work_free(work); + } +} + + static void radio_remove_interface(struct wpa_supplicant *wpa_s) { struct wpa_radio *radio = wpa_s->radio; @@ -2934,16 +3095,112 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s", wpa_s->ifname, radio->name); dl_list_del(&wpa_s->radio_list); - wpa_s->radio = NULL; - - if (!dl_list_empty(&radio->ifaces)) + if (!dl_list_empty(&radio->ifaces)) { + wpa_s->radio = NULL; return; /* Interfaces remain for this radio */ + } wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name); + radio_remove_unstarted_work(wpa_s, NULL); + eloop_cancel_timeout(radio_start_next_work, radio, NULL); + wpa_s->radio = NULL; os_free(radio); } +void radio_work_check_next(struct wpa_supplicant *wpa_s) +{ + struct wpa_radio *radio = wpa_s->radio; + + if (dl_list_empty(&radio->work)) + return; + eloop_cancel_timeout(radio_start_next_work, radio, NULL); + eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL); +} + + +/** + * radio_add_work - Add a radio work item + * @wpa_s: Pointer to wpa_supplicant data + * @freq: Frequency of the offchannel operation in MHz or 0 + * @type: Unique identifier for each type of work + * @next: Force as the next work to be executed + * @cb: Callback function for indicating when radio is available + * @ctx: Context pointer for the work (work->ctx in cb()) + * Returns: 0 on success, -1 on failure + * + * This function is used to request time for an operation that requires + * exclusive radio control. Once the radio is available, the registered callback + * function will be called. radio_work_done() must be called once the exclusive + * radio operation has been completed, so that the radio is freed for other + * operations. The special case of deinit=1 is used to free the context data + * during interface removal. That does not allow the callback function to start + * the radio operation, i.e., it must free any resources allocated for the radio + * work and return. + * + * The @freq parameter can be used to indicate a single channel on which the + * offchannel operation will occur. This may allow multiple radio work + * operations to be performed in parallel if they apply for the same channel. + * Setting this to 0 indicates that the work item may use multiple channels or + * requires exclusive control of the radio. + */ +int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, + const char *type, int next, + void (*cb)(struct wpa_radio_work *work, int deinit), + void *ctx) +{ + struct wpa_radio_work *work; + int was_empty; + + work = os_zalloc(sizeof(*work)); + if (work == NULL) + return -1; + wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work); + os_get_reltime(&work->time); + work->freq = freq; + work->type = type; + work->wpa_s = wpa_s; + work->cb = cb; + work->ctx = ctx; + + was_empty = dl_list_empty(&wpa_s->radio->work); + if (next) + dl_list_add(&wpa_s->radio->work, &work->list); + else + dl_list_add_tail(&wpa_s->radio->work, &work->list); + if (was_empty) { + wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately"); + radio_work_check_next(wpa_s); + } + + return 0; +} + + +/** + * radio_work_done - Indicate that a radio work item has been completed + * @work: Completed work + * + * This function is called once the callback function registered with + * radio_add_work() has completed its work. + */ +void radio_work_done(struct wpa_radio_work *work) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct os_reltime now, diff; + unsigned int started = work->started; + + os_get_reltime(&now); + os_reltime_sub(&now, &work->time, &diff); + wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds", + work->type, work, started ? "done" : "canceled", + diff.sec, diff.usec); + radio_work_free(work); + if (started) + radio_work_check_next(wpa_s); +} + + static int wpas_init_driver(struct wpa_supplicant *wpa_s, struct wpa_interface *iface) { @@ -3263,6 +3520,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ + wpas_ctrl_radio_work_flush(wpa_s); radio_remove_interface(wpa_s); if (wpa_s->drv_priv) @@ -3751,6 +4009,8 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) int count; int *freqs = NULL; + wpas_connect_work_done(wpa_s); + /* * Remove possible authentication timeout since the connection failed. */ @@ -3837,8 +4097,6 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) */ wpa_supplicant_req_scan(wpa_s, timeout / 1000, 1000 * (timeout % 1000)); - - wpas_p2p_continue_after_scan(wpa_s); } @@ -3978,7 +4236,7 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid = wpa_s->current_ssid; int dur; - struct os_time now; + struct os_reltime now; if (ssid == NULL) { wpa_printf(MSG_DEBUG, "Authentication failure but no known " @@ -4015,7 +4273,7 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s) else dur = 10; - os_get_time(&now); + os_get_reltime(&now); if (now.sec + dur <= ssid->disabled_until.sec) return; @@ -4103,42 +4361,6 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s) } -static int wpas_conn_in_progress(struct wpa_supplicant *wpa_s) -{ - return wpa_s->wpa_state >= WPA_AUTHENTICATING && - wpa_s->wpa_state != WPA_COMPLETED; -} - - -/** - * wpas_wpa_is_in_progress - Check whether a connection is in progress - * @wpa_s: Pointer to wpa_supplicant data - * @include_current: Whether to consider specified interface - * - * This function is to check if the wpa state is in beginning of the connection - * during 4-way handshake or group key handshake with WPA on any shared - * interface. - */ -int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current) -{ - struct wpa_supplicant *ifs; - - dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, - radio_list) { - if (!include_current && ifs == wpa_s) - continue; - - if (wpas_conn_in_progress(ifs)) { - wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress " - "on interface %s - defer", ifs->ifname); - return 1; - } - } - - return 0; -} - - void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title, int *freq_array, unsigned int len) { diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 0ecfaa68..9d3bf6d5 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -342,6 +342,8 @@ fast_reauth=1 # # credential fields: # +# temporary: Whether this credential is temporary and not to be saved +# # priority: Priority group # By default, all networks and credentials get the same priority group # (0). This field can be used to give higher priority for credentials @@ -506,9 +508,10 @@ fast_reauth=1 # 0 = infrastructure (Managed) mode, i.e., associate with an AP (default) # 1 = IBSS (ad-hoc, peer-to-peer) # 2 = AP (access point) -# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) -# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). WPA-None requires -# following network block options: +# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) and +# WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE (fixed group key +# TKIP/CCMP) is available for backwards compatibility, but its use is +# deprecated. WPA-None requires following network block options: # proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not # both), and psk must also be set. # @@ -1163,7 +1166,19 @@ network={ } -# IBSS/ad-hoc network with WPA-None/TKIP. +# IBSS/ad-hoc network with RSN +network={ + ssid="ibss-rsn" + key_mgmt=WPA-PSK + proto=RSN + psk="12345678" + mode=1 + frequency=2412 + pairwise=CCMP + group=CCMP +} + +# IBSS/ad-hoc network with WPA-None/TKIP (deprecated) network={ ssid="test adhoc" mode=1 diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 8cc813c8..d1ea77bb 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Internal definitions - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -246,7 +246,7 @@ struct wpa_global { struct wpa_supplicant *p2p_group_formation; struct wpa_supplicant *p2p_invite_group; u8 p2p_dev_addr[ETH_ALEN]; - struct os_time p2p_go_wait_client; + struct os_reltime p2p_go_wait_client; struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */ struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */ int p2p_disabled; @@ -257,8 +257,8 @@ struct wpa_global { WPA_CONC_PREF_STA, WPA_CONC_PREF_P2P } conc_pref; - unsigned int p2p_cb_on_scan_complete:1; unsigned int p2p_per_sta_psk:1; + unsigned int p2p_fail_on_wps_complete:1; #ifdef CONFIG_WIFI_DISPLAY int wifi_display; @@ -281,6 +281,47 @@ struct wpa_radio { char name[16]; /* from driver_ops get_radio_name() or empty if not * available */ struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */ + struct dl_list work; /* struct wpa_radio_work::list entries */ +}; + +/** + * struct wpa_radio_work - Radio work item + */ +struct wpa_radio_work { + struct dl_list list; + unsigned int freq; /* known frequency (MHz) or 0 for multiple/unknown */ + const char *type; + struct wpa_supplicant *wpa_s; + void (*cb)(struct wpa_radio_work *work, int deinit); + void *ctx; + unsigned int started:1; + struct os_reltime time; +}; + +int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, + const char *type, int next, + void (*cb)(struct wpa_radio_work *work, int deinit), + void *ctx); +void radio_work_done(struct wpa_radio_work *work); +void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s, + const char *type); +void radio_work_check_next(struct wpa_supplicant *wpa_s); + +struct wpa_connect_work { + unsigned int sme:1; + struct wpa_bss *bss; + struct wpa_ssid *ssid; +}; + +int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss, + struct wpa_ssid *test_ssid); +void wpas_connect_work_free(struct wpa_connect_work *cwork); +void wpas_connect_work_done(struct wpa_supplicant *wpa_s); + +struct wpa_external_work { + unsigned int id; + char type[100]; + unsigned int timeout; }; /** @@ -302,7 +343,7 @@ struct wps_ap_info { WPS_AP_SEL_REG_OUR } type; unsigned int tries; - struct os_time last_attempt; + struct os_reltime last_attempt; }; struct wpa_ssid_value { @@ -344,7 +385,7 @@ struct wpa_supplicant { char *confanother; struct wpa_config *conf; int countermeasures; - os_time_t last_michael_mic_error; + struct os_reltime last_michael_mic_error; u8 bssid[ETH_ALEN]; u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this * field contains the target BSSID. */ @@ -408,8 +449,7 @@ struct wpa_supplicant { struct wpa_bss **last_scan_res; unsigned int last_scan_res_used; unsigned int last_scan_res_size; - int last_scan_full; - struct os_time last_scan; + struct os_reltime last_scan; struct wpa_driver_ops *driver; int interface_removed; /* whether the network interface has been @@ -420,6 +460,7 @@ struct wpa_supplicant { struct ctrl_iface_priv *ctrl_iface; enum wpa_states wpa_state; + struct wpa_radio_work *scan_work; int scanning; int sched_scanning; int new_connection; @@ -433,7 +474,8 @@ struct wpa_supplicant { unsigned char last_eapol_src[ETH_ALEN]; - int keys_cleared; + unsigned int keys_cleared; /* bitfield of key indexes that the driver is + * known not to be configured with a key */ struct wpa_blacklist *blacklist; @@ -479,9 +521,18 @@ struct wpa_supplicant { */ MANUAL_SCAN_REQ } scan_req, last_scan_req; - struct os_time scan_trigger_time; + struct os_reltime scan_trigger_time, scan_start_time; int scan_runs; /* number of scan runs since WPS was started */ int *next_scan_freqs; + int *manual_scan_freqs; + unsigned int manual_scan_passive:1; + unsigned int manual_scan_use_id:1; + unsigned int manual_scan_only_new:1; + unsigned int own_scan_requested:1; + unsigned int own_scan_running:1; + unsigned int external_scan_running:1; + unsigned int clear_driver_scan_cache:1; + unsigned int manual_scan_id; int scan_interval; /* time in sec between scans to find suitable AP */ int normal_scans; /* normal scans run before sched_scan */ int scan_for_connection; /* whether the scan request was triggered for @@ -517,7 +568,7 @@ struct wpa_supplicant { int blacklist_cleared; struct wpabuf *pending_eapol_rx; - struct os_time pending_eapol_rx_time; + struct os_reltime pending_eapol_rx_time; u8 pending_eapol_rx_src[ETH_ALEN]; unsigned int last_eapol_matches_bssid:1; @@ -551,7 +602,7 @@ struct wpa_supplicant { u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * * sa_query_count octets of pending * SA Query transaction identifiers */ - struct os_time sa_query_start; + struct os_reltime sa_query_start; u8 sched_obss_scan; u16 obss_scan_int; u16 bss_max_idle_period; @@ -647,7 +698,6 @@ struct wpa_supplicant { */ char cross_connect_uplink[100]; - unsigned int sta_scan_pending:1; unsigned int p2p_auto_join:1; unsigned int p2p_auto_pd:1; unsigned int p2p_persistent_group:1; @@ -657,13 +707,17 @@ struct wpa_supplicant { unsigned int p2p_go_vht:1; unsigned int user_initiated_pd:1; unsigned int p2p_go_group_formation_completed:1; + unsigned int waiting_presence_resp; int p2p_first_connection_timeout; int p2p_persistent_go_freq; int p2p_persistent_id; int p2p_go_intent; int p2p_connect_freq; - struct os_time p2p_auto_started; + struct os_reltime p2p_auto_started; struct wpa_ssid *p2p_last_4way_hs_fail; + struct wpa_radio_work *p2p_scan_work; + struct wpa_radio_work *p2p_listen_work; + struct wpa_radio_work *p2p_send_action_work; #endif /* CONFIG_P2P */ struct wpa_ssid *bgscan_ssid; @@ -717,9 +771,9 @@ struct wpa_supplicant { struct ext_password_data *ext_pw; - struct wpabuf *last_gas_resp; - u8 last_gas_addr[ETH_ALEN]; - u8 last_gas_dialog_token; + struct wpabuf *last_gas_resp, *prev_gas_resp; + u8 last_gas_addr[ETH_ALEN], prev_gas_addr[ETH_ALEN]; + u8 last_gas_dialog_token, prev_gas_dialog_token; unsigned int no_keep_alive:1; @@ -740,6 +794,9 @@ struct wpa_supplicant { #endif /* CONFIG_TESTING_GET_GTK */ unsigned int num_multichan_concurrent; + struct wpa_radio_work *connect_work; + + unsigned int ext_work_id; }; @@ -821,7 +878,6 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, void wpa_supplicant_terminate_proc(struct wpa_global *global); void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, const u8 *buf, size_t len); -enum wpa_key_mgmt key_mgmt2driver(int key_mgmt); void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s); void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid); @@ -835,7 +891,6 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len); void wpas_request_connection(struct wpa_supplicant *wpa_s); int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf); -int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current); /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 0b3c8922..038c7fae 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -1,6 +1,6 @@ /* * wpa_supplicant / WPS integration - * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -54,6 +54,11 @@ static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s) int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) { +#ifdef CONFIG_P2P + if (wpas_p2p_wps_eapol_cb(wpa_s) > 0) + return 1; +#endif /* CONFIG_P2P */ + if (!wpa_s->wps_success && wpa_s->current_ssid && eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) { @@ -260,31 +265,6 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s, ssid->group_cipher != new_ssid->group_cipher) continue; - if (ssid->passphrase && new_ssid->passphrase) { - if (os_strlen(ssid->passphrase) != - os_strlen(new_ssid->passphrase)) - continue; - if (os_strcmp(ssid->passphrase, new_ssid->passphrase) != - 0) - continue; - } else if (ssid->passphrase || new_ssid->passphrase) - continue; - - if ((ssid->psk_set || new_ssid->psk_set) && - os_memcmp(ssid->psk, new_ssid->psk, sizeof(ssid->psk)) != 0) - continue; - - if (ssid->auth_alg == WPA_ALG_WEP) { - if (ssid->wep_tx_keyidx != new_ssid->wep_tx_keyidx) - continue; - if (os_memcmp(ssid->wep_key, new_ssid->wep_key, - sizeof(ssid->wep_key))) - continue; - if (os_memcmp(ssid->wep_key_len, new_ssid->wep_key_len, - sizeof(ssid->wep_key_len))) - continue; - } - /* Remove the duplicated older network entry. */ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id); wpas_notify_network_removed(wpa_s, ssid); @@ -891,6 +871,7 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s) wpas_wps_reenable_networks(wpa_s); eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL); /* Remove any existing WPS network from configuration */ ssid = wpa_s->conf->ssid; @@ -1160,6 +1141,9 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s) } else { wpas_wps_reenable_networks(wpa_s); wpas_wps_clear_ap_info(wpa_s); + if (eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL) > + 0) + wpas_clear_wps(wpa_s); } wpa_s->after_wps = 0; @@ -1298,7 +1282,9 @@ static u16 wps_fix_config_methods(u16 config_methods) static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s, struct wps_context *wps) { - wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname); + char buf[50]; + const char *src; + if (is_nil_uuid(wpa_s->conf->uuid)) { struct wpa_supplicant *first; first = wpa_s->global->ifaces; @@ -1309,18 +1295,18 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s, os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid, WPS_UUID_LEN); - wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first " - "interface", wps->uuid, WPS_UUID_LEN); + src = "from the first interface"; } else { uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid); - wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " - "address", wps->uuid, WPS_UUID_LEN); + src = "based on MAC address"; } } else { os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); - wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration", - wps->uuid, WPS_UUID_LEN); + src = "based on configuration"; } + + uuid_bin2str(wps->uuid, buf, sizeof(buf)); + wpa_dbg(wpa_s, MSG_DEBUG, "WPS: UUID %s: %s", src, buf); } @@ -1959,19 +1945,6 @@ int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s) } -int wpas_wps_in_progress(struct wpa_supplicant *wpa_s) -{ - struct wpa_ssid *ssid; - - for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { - if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS) - return 1; - } - - return 0; -} - - void wpas_wps_update_config(struct wpa_supplicant *wpa_s) { struct wps_context *wps = wpa_s->wps; @@ -2260,8 +2233,9 @@ struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr) #ifdef CONFIG_WPS_NFC -struct wpabuf * wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, - int ndef, const char *uuid) +static struct wpabuf * +wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s, int ndef, + const char *uuid) { #ifdef CONFIG_WPS_ER struct wpabuf *ret; @@ -2355,12 +2329,10 @@ int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WPS_NFC */ -extern int wpa_debug_level; - static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s) { size_t i; - struct os_time now; + struct os_reltime now; if (wpa_debug_level > MSG_DEBUG) return; @@ -2368,7 +2340,7 @@ static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s) if (wpa_s->wps_ap == NULL) return; - os_get_time(&now); + os_get_reltime(&now); for (i = 0; i < wpa_s->num_wps_ap; i++) { struct wps_ap_info *ap = &wpa_s->wps_ap[i]; @@ -2481,5 +2453,5 @@ void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) if (ap == NULL) return; ap->tries++; - os_get_time(&ap->last_attempt); + os_get_reltime(&ap->last_attempt); } diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index 2a212cab..3fcfbbe1 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -60,7 +60,6 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid, struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *uuid); int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s); -int wpas_wps_in_progress(struct wpa_supplicant *wpa_s); void wpas_wps_update_config(struct wpa_supplicant *wpa_s); struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef, const char *id_str); |
